|  | /* RTL reader for GCC. | 
|  | Copyright (C) 1987-2025 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GCC. | 
|  |  | 
|  | GCC is free software; you can redistribute it and/or modify it under | 
|  | the terms of the GNU General Public License as published by the Free | 
|  | Software Foundation; either version 3, or (at your option) any later | 
|  | version. | 
|  |  | 
|  | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | 
|  | WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|  | for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with GCC; see the file COPYING3.  If not see | 
|  | <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | /* This file is compiled twice: once for the generator programs | 
|  | once for the compiler.  */ | 
|  | #ifdef GENERATOR_FILE | 
|  | #include "bconfig.h" | 
|  | #else | 
|  | #include "config.h" | 
|  | #endif | 
|  |  | 
|  | /* Disable rtl checking; it conflicts with the iterator handling.  */ | 
|  | #undef ENABLE_RTL_CHECKING | 
|  |  | 
|  | #include "system.h" | 
|  | #include "coretypes.h" | 
|  | #include "tm.h" | 
|  | #include "rtl.h" | 
|  | #include "obstack.h" | 
|  | #include "read-md.h" | 
|  | #include "gensupport.h" | 
|  |  | 
|  | /* One element in a singly-linked list of (integer, string) pairs.  */ | 
|  | struct map_value { | 
|  | struct map_value *next; | 
|  | int number; | 
|  | const char *string; | 
|  | }; | 
|  |  | 
|  | /* Maps an iterator or attribute name to a list of (integer, string) pairs. | 
|  | The integers are iterator values; the strings are either C conditions | 
|  | or attribute values.  */ | 
|  | struct mapping { | 
|  | /* The name of the iterator or attribute.  */ | 
|  | const char *name; | 
|  |  | 
|  | /* The group (modes or codes) to which the iterator or attribute belongs.  */ | 
|  | struct iterator_group *group; | 
|  |  | 
|  | /* 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 iterators.  */ | 
|  | struct iterator_group { | 
|  | /* Tables of "mapping" structures, one for attributes and one for | 
|  | iterators.  */ | 
|  | htab_t attrs, iterators; | 
|  |  | 
|  | /* The C++ type of the iterator, such as "machine_mode" for modes.  */ | 
|  | const char *type; | 
|  |  | 
|  | /* Treat the given string as the name of a standard mode, etc., and | 
|  | return its integer value.  */ | 
|  | HOST_WIDE_INT (*find_builtin) (const char *); | 
|  |  | 
|  | /* 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, HOST_WIDE_INT); | 
|  |  | 
|  | /* Return the C token for the given standard mode, code, etc.  */ | 
|  | const char *(*get_c_token) (int); | 
|  |  | 
|  | /* True if each iterator name should be treated as an attribute that | 
|  | maps to the C token produced by get_c_token.  This means that for | 
|  | an iterator ITER, <ITER> can be used in strings to refer to the | 
|  | current value of ITER, as a C token.  */ | 
|  | bool has_self_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; | 
|  | }; | 
|  |  | 
|  | /* Records one use of an attribute (the "<[iterator:]attribute>" syntax) | 
|  | in a non-string rtx field.  */ | 
|  | struct attribute_use { | 
|  | /* The group that describes the use site.  */ | 
|  | struct iterator_group *group; | 
|  |  | 
|  | /* The location at which the use occurs.  */ | 
|  | file_location loc; | 
|  |  | 
|  | /* The name of the attribute, possibly with an "iterator:" prefix.  */ | 
|  | const char *value; | 
|  |  | 
|  | /* The location of the use, as passed to GROUP's apply_iterator callback. | 
|  | The index is the number of the operand that used the iterator | 
|  | if applicable, otherwise it is ignored.  */ | 
|  | rtx x; | 
|  | unsigned int index; | 
|  | }; | 
|  |  | 
|  | /* 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 void one_time_initialization (void); | 
|  |  | 
|  | /* Global singleton.  */ | 
|  | rtx_reader *rtx_reader_ptr = NULL; | 
|  |  | 
|  | /* The mode and code iterator structures.  */ | 
|  | static struct iterator_group modes, codes, ints, substs; | 
|  |  | 
|  | /* All iterators used in the current rtx.  */ | 
|  | static vec<mapping *> current_iterators; | 
|  |  | 
|  | /* 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; | 
|  |  | 
|  | /* 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			\ | 
|  | && !HAVE_DECL_ATOLL						\ | 
|  | && !defined (HAVE_ATOQ)) | 
|  | HOST_WIDE_INT atoll (const char *); | 
|  |  | 
|  | HOST_WIDE_INT | 
|  | atoll (const char *p) | 
|  | { | 
|  | int neg = 0; | 
|  | HOST_WIDE_INT tmp_wide; | 
|  |  | 
|  | while (ISSPACE (*p)) | 
|  | p++; | 
|  | if (*p == '-') | 
|  | neg = 1, p++; | 
|  | else if (*p == '+') | 
|  | p++; | 
|  |  | 
|  | tmp_wide = 0; | 
|  | while (ISDIGIT (*p)) | 
|  | { | 
|  | HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0'); | 
|  | if (new_wide < tmp_wide) | 
|  | { | 
|  | /* Return INT_MAX equiv on overflow.  */ | 
|  | tmp_wide = HOST_WIDE_INT_M1U >> 1; | 
|  | break; | 
|  | } | 
|  | tmp_wide = new_wide; | 
|  | p++; | 
|  | } | 
|  |  | 
|  | if (neg) | 
|  | tmp_wide = -tmp_wide; | 
|  | return tmp_wide; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* Implementations of the iterator_group callbacks for modes.  */ | 
|  |  | 
|  | static HOST_WIDE_INT | 
|  | find_mode (const char *name) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < NUM_MACHINE_MODES; i++) | 
|  | if (strcmp (GET_MODE_NAME (i), name) == 0) | 
|  | return i; | 
|  |  | 
|  | fatal_with_file_and_line ("unknown mode `%s'", name); | 
|  | } | 
|  |  | 
|  | static void | 
|  | apply_mode_iterator (rtx x, unsigned int, HOST_WIDE_INT mode) | 
|  | { | 
|  | PUT_MODE (x, (machine_mode) mode); | 
|  | } | 
|  |  | 
|  | static const char * | 
|  | get_mode_token (int mode) | 
|  | { | 
|  | return concat ("E_", GET_MODE_NAME (mode), "mode", NULL); | 
|  | } | 
|  |  | 
|  | /* In compact dumps, the code of insns is prefixed with "c", giving "cinsn", | 
|  | "cnote" etc, and CODE_LABEL is special-cased as "clabel".  */ | 
|  |  | 
|  | struct compact_insn_name { | 
|  | RTX_CODE code; | 
|  | const char *name; | 
|  | }; | 
|  |  | 
|  | static const compact_insn_name compact_insn_names[] = { | 
|  | { DEBUG_INSN, "cdebug_insn" }, | 
|  | { INSN, "cinsn" }, | 
|  | { JUMP_INSN, "cjump_insn" }, | 
|  | { CALL_INSN, "ccall_insn" }, | 
|  | { JUMP_TABLE_DATA, "cjump_table_data" }, | 
|  | { BARRIER, "cbarrier" }, | 
|  | { CODE_LABEL, "clabel" }, | 
|  | { NOTE, "cnote" } | 
|  | }; | 
|  |  | 
|  | /* Return the rtx code for NAME, or UNKNOWN if NAME isn't a valid rtx code.  */ | 
|  |  | 
|  | static rtx_code | 
|  | maybe_find_code (const char *name) | 
|  | { | 
|  | for (int i = 0; i < NUM_RTX_CODE; i++) | 
|  | if (strcmp (GET_RTX_NAME (i), name) == 0) | 
|  | return (rtx_code) i; | 
|  |  | 
|  | for (int i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++) | 
|  | if (strcmp (compact_insn_names[i].name, name) == 0) | 
|  | return compact_insn_names[i].code; | 
|  |  | 
|  | return UNKNOWN; | 
|  | } | 
|  |  | 
|  | /* Implementations of the iterator_group callbacks for codes.  */ | 
|  |  | 
|  | static HOST_WIDE_INT | 
|  | find_code (const char *name) | 
|  | { | 
|  | rtx_code code = maybe_find_code (name); | 
|  | if (code == UNKNOWN) | 
|  | fatal_with_file_and_line ("unknown rtx code `%s'", name); | 
|  | return code; | 
|  | } | 
|  |  | 
|  | static void | 
|  | apply_code_iterator (rtx x, unsigned int, HOST_WIDE_INT code) | 
|  | { | 
|  | PUT_CODE (x, (enum rtx_code) code); | 
|  | } | 
|  |  | 
|  | static const char * | 
|  | get_code_token (int code) | 
|  | { | 
|  | char *name = xstrdup (GET_RTX_NAME (code)); | 
|  | for (int i = 0; name[i]; ++i) | 
|  | name[i] = TOUPPER (name[i]); | 
|  | return name; | 
|  | } | 
|  |  | 
|  | /* Implementations of the iterator_group callbacks for ints.  */ | 
|  |  | 
|  | /* 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 HOST_WIDE_INT | 
|  | find_int (const char *name) | 
|  | { | 
|  | HOST_WIDE_INT tmp; | 
|  |  | 
|  | struct md_constant tmp_def; | 
|  | tmp_def.name = const_cast<char *> (name); | 
|  | auto htab = rtx_reader_ptr->get_md_constants (); | 
|  | if (auto def = (struct md_constant *) htab_find (htab, &tmp_def)) | 
|  | name = def->value; | 
|  |  | 
|  | validate_const_int (name); | 
|  | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT | 
|  | tmp = atoi (name); | 
|  | #else | 
|  | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG | 
|  | tmp = atol (name); | 
|  | #else | 
|  | /* Prefer atoll over atoq, since the former is in the ISO C99 standard. | 
|  | But prefer not to use our hand-rolled function above either.  */ | 
|  | #if HAVE_DECL_ATOLL || !defined(HAVE_ATOQ) | 
|  | tmp = atoll (name); | 
|  | #else | 
|  | tmp = atoq (name); | 
|  | #endif | 
|  | #endif | 
|  | #endif | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | static void | 
|  | apply_int_iterator (rtx x, unsigned int index, HOST_WIDE_INT value) | 
|  | { | 
|  | RTX_CODE code = GET_CODE (x); | 
|  | const char *format_ptr = GET_RTX_FORMAT (code); | 
|  |  | 
|  | switch (format_ptr[index]) | 
|  | { | 
|  | case 'i': | 
|  | case 'n': | 
|  | XINT (x, index) = value; | 
|  | break; | 
|  | case 'L': | 
|  | XLOC (x, index) = value; | 
|  | break; | 
|  | case 'w': | 
|  | XWINT (x, index) = value; | 
|  | break; | 
|  | case 'p': | 
|  | gcc_assert (code == SUBREG); | 
|  | SUBREG_BYTE (x) = value; | 
|  | break; | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  | } | 
|  |  | 
|  | static const char * | 
|  | get_int_token (int value) | 
|  | { | 
|  | char buffer[HOST_BITS_PER_INT + 1]; | 
|  | sprintf (buffer, "%d", value); | 
|  | return xstrdup (buffer); | 
|  | } | 
|  |  | 
|  | #ifdef GENERATOR_FILE | 
|  |  | 
|  | /* This routine adds attribute or does nothing depending on VALUE.  When | 
|  | VALUE is 1, it does nothing - the first duplicate of original | 
|  | template is kept untouched when it's subjected to a define_subst. | 
|  | When VALUE isn't 1, the routine modifies RTL-template 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, HOST_WIDE_INT value) | 
|  | { | 
|  | rtx new_attr; | 
|  | rtvec attrs_vec, new_attrs_vec; | 
|  | int i; | 
|  | /* define_split has no attributes.  */ | 
|  | if (value == 1 || GET_CODE (rt) == DEFINE_SPLIT) | 
|  | return; | 
|  | gcc_assert (GET_CODE (rt) == DEFINE_INSN | 
|  | || GET_CODE (rt) == DEFINE_INSN_AND_SPLIT | 
|  | || GET_CODE (rt) == DEFINE_INSN_AND_REWRITE | 
|  | || GET_CODE (rt) == DEFINE_EXPAND); | 
|  |  | 
|  | int attrs = (GET_CODE (rt) == DEFINE_INSN_AND_SPLIT ? 7 | 
|  | : GET_CODE (rt) == DEFINE_INSN_AND_REWRITE ? 6 : 4); | 
|  | attrs_vec = XVEC (rt, attrs); | 
|  |  | 
|  | /* If we've already added attribute 'current_iterator_name', then we | 
|  | have nothing to do now.  */ | 
|  | 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, attrs) = 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.  If ITERATOR_OUT is nonnull, store the associated iterator | 
|  | there.  Report any errors against location LOC.  */ | 
|  |  | 
|  | static struct map_value * | 
|  | map_attr_string (file_location loc, const char *p, mapping **iterator_out = 0) | 
|  | { | 
|  | const char *attr; | 
|  | struct mapping *iterator; | 
|  | unsigned int i; | 
|  | struct mapping *m; | 
|  | struct map_value *v; | 
|  | int iterator_name_len; | 
|  | struct map_value *res = NULL; | 
|  | struct mapping *prev = NULL; | 
|  |  | 
|  | /* Peel off any "iterator:" prefix.  Set ATTR to the start of the | 
|  | attribute name.  */ | 
|  | attr = strchr (p, ':'); | 
|  | if (attr == 0) | 
|  | { | 
|  | iterator_name_len = -1; | 
|  | attr = p; | 
|  | } | 
|  | else | 
|  | { | 
|  | iterator_name_len = attr - p; | 
|  | attr++; | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | if (iterator->group->has_self_attr | 
|  | && strcmp (attr, iterator->name) == 0) | 
|  | { | 
|  | if (iterator_out) | 
|  | *iterator_out = iterator; | 
|  | int number = iterator->current_value->number; | 
|  | const char *string = iterator->group->get_c_token (number); | 
|  | if (res && strcmp (string, res->string) != 0) | 
|  | { | 
|  | error_at (loc, "ambiguous attribute '%s'; could be" | 
|  | " '%s' (via '%s:%s') or '%s' (via '%s:%s')", | 
|  | attr, res->string, prev->name, attr, | 
|  | string, iterator->name, attr); | 
|  | return res; | 
|  | } | 
|  | prev = iterator; | 
|  | res = new map_value { nullptr, number, string }; | 
|  | } | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | if (res && strcmp (v->string, res->string) != 0) | 
|  | { | 
|  | error_at (loc, "ambiguous attribute '%s'; could be" | 
|  | " '%s' (via '%s:%s') or '%s' (via '%s:%s')", | 
|  | attr, res->string, prev->name, attr, | 
|  | v->string, iterator->name, attr); | 
|  | return v; | 
|  | } | 
|  | if (iterator_out) | 
|  | *iterator_out = iterator; | 
|  | prev = iterator; | 
|  | res = v; | 
|  | } | 
|  | } | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* Apply the current iterator values to STRING.  Return the new string | 
|  | if any changes were needed, otherwise return STRING itself.  */ | 
|  |  | 
|  | const char * | 
|  | md_reader::apply_iterator_to_string (const char *string) | 
|  | { | 
|  | char *base, *copy, *p, *start, *end; | 
|  | struct map_value *v; | 
|  |  | 
|  | if (string == 0 || string[0] == 0) | 
|  | return string; | 
|  |  | 
|  | file_location loc = get_md_ptr_loc (string)->loc; | 
|  | base = p = copy = ASTRDUP (string); | 
|  | while ((start = strchr (p, '<')) && (end = strchr (start, '>'))) | 
|  | { | 
|  | p = start + 1; | 
|  |  | 
|  | *end = 0; | 
|  | v = map_attr_string (loc, p); | 
|  | *end = '>'; | 
|  | if (v == 0) | 
|  | continue; | 
|  |  | 
|  | /* Add everything between the last copied byte and the '<', | 
|  | then add in the attribute value.  */ | 
|  | 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 (&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 deep copy of X, substituting the current iterator | 
|  | values into any strings.  */ | 
|  |  | 
|  | rtx | 
|  | md_reader::copy_rtx_for_iterators (rtx original) | 
|  | { | 
|  | const char *format_ptr, *p; | 
|  | int i, j; | 
|  | rtx x; | 
|  |  | 
|  | if (original == 0) | 
|  | return original; | 
|  |  | 
|  | /* Create a shallow copy of ORIGINAL.  */ | 
|  | 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 (GET_CODE (original)); | 
|  | for (i = 0; format_ptr[i] != 0; i++) | 
|  | switch (format_ptr[i]) | 
|  | { | 
|  | case 'T': | 
|  | while (XTMPL (x, i) != (p = apply_iterator_to_string (XTMPL (x, i)))) | 
|  | XTMPL (x, i) = p; | 
|  | break; | 
|  |  | 
|  | case 'S': | 
|  | case 's': | 
|  | while (XSTR (x, i) != (p = apply_iterator_to_string (XSTR (x, i)))) | 
|  | XSTR (x, i) = p; | 
|  | break; | 
|  |  | 
|  | case 'e': | 
|  | XEXP (x, i) = copy_rtx_for_iterators (XEXP (x, i)); | 
|  | break; | 
|  |  | 
|  | case 'V': | 
|  | case 'E': | 
|  | if (XVEC (original, i)) | 
|  | { | 
|  | XVEC (x, i) = rtvec_alloc (XVECLEN (original, i)); | 
|  | for (j = 0; j < XVECLEN (x, i); j++) | 
|  | XVECEXP (x, i, j) | 
|  | = copy_rtx_for_iterators (XVECEXP (original, i, j)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return x; | 
|  | } | 
|  |  | 
|  | #ifdef GENERATOR_FILE | 
|  |  | 
|  | /* Return a condition that must satisfy both ORIGINAL and EXTRA.  If ORIGINAL | 
|  | has the form "&& ..." (as used in define_insn_and_splits), assume that | 
|  | EXTRA is already satisfied.  Empty strings are treated like "true".  */ | 
|  |  | 
|  | static const char * | 
|  | add_condition_to_string (const char *original, const char *extra) | 
|  | { | 
|  | if (original != 0 && original[0] == '&' && original[1] == '&') | 
|  | return original; | 
|  | return rtx_reader_ptr->join_c_conditions (original, extra); | 
|  | } | 
|  |  | 
|  | /* Like add_condition, but applied to all conditions in rtx X.  */ | 
|  |  | 
|  | static void | 
|  | add_condition_to_rtx (rtx x, const char *extra) | 
|  | { | 
|  | switch (GET_CODE (x)) | 
|  | { | 
|  | case DEFINE_INSN: | 
|  | case DEFINE_EXPAND: | 
|  | case DEFINE_SUBST: | 
|  | XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); | 
|  | break; | 
|  |  | 
|  | case DEFINE_SPLIT: | 
|  | case DEFINE_PEEPHOLE: | 
|  | case DEFINE_PEEPHOLE2: | 
|  | case DEFINE_COND_EXEC: | 
|  | XSTR (x, 1) = add_condition_to_string (XSTR (x, 1), extra); | 
|  | break; | 
|  |  | 
|  | case DEFINE_INSN_AND_SPLIT: | 
|  | case DEFINE_INSN_AND_REWRITE: | 
|  | XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); | 
|  | XSTR (x, 4) = add_condition_to_string (XSTR (x, 4), extra); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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->loc, 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 | 
|  | add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED) | 
|  | { | 
|  | struct mapping *iterator; | 
|  |  | 
|  | iterator = (struct mapping *) *slot; | 
|  | if (iterator->current_value) | 
|  | current_iterators.safe_push (iterator); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Return a hash value for overloaded_name UNCAST_ONAME.  There shouldn't | 
|  | be many instances of two overloaded_names having the same name but | 
|  | different arguments, so hashing on the name should be good enough in | 
|  | practice.  */ | 
|  |  | 
|  | static hashval_t | 
|  | overloaded_name_hash (const void *uncast_oname) | 
|  | { | 
|  | const overloaded_name *oname = (const overloaded_name *) uncast_oname; | 
|  | return htab_hash_string (oname->name); | 
|  | } | 
|  |  | 
|  | /* Return true if two overloaded_names are similar enough to share | 
|  | the same generated functions.  */ | 
|  |  | 
|  | static int | 
|  | overloaded_name_eq_p (const void *uncast_oname1, const void *uncast_oname2) | 
|  | { | 
|  | const overloaded_name *oname1 = (const overloaded_name *) uncast_oname1; | 
|  | const overloaded_name *oname2 = (const overloaded_name *) uncast_oname2; | 
|  | if (strcmp (oname1->name, oname2->name) != 0 | 
|  | || oname1->arg_types.length () != oname2->arg_types.length ()) | 
|  | return 0; | 
|  |  | 
|  | for (unsigned int i = 0; i < oname1->arg_types.length (); ++i) | 
|  | if (strcmp (oname1->arg_types[i], oname2->arg_types[i]) != 0) | 
|  | return 0; | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Return true if X has an instruction name in XSTR (X, 0).  */ | 
|  |  | 
|  | static bool | 
|  | named_rtx_p (rtx x) | 
|  | { | 
|  | switch (GET_CODE (x)) | 
|  | { | 
|  | case DEFINE_EXPAND: | 
|  | case DEFINE_INSN: | 
|  | case DEFINE_INSN_AND_SPLIT: | 
|  | case DEFINE_INSN_AND_REWRITE: | 
|  | return true; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Check whether ORIGINAL is a named pattern whose name starts with '@'. | 
|  | If so, return the associated overloaded_name and add the iterator for | 
|  | each argument to ITERATORS.  Return null otherwise.  */ | 
|  |  | 
|  | overloaded_name * | 
|  | md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators) | 
|  | { | 
|  | /* Check for the leading '@'.  */ | 
|  | if (!named_rtx_p (original) || XSTR (original, 0)[0] != '@') | 
|  | return NULL; | 
|  |  | 
|  | /* Remove the '@', so that no other code needs to worry about it.  */ | 
|  | const char *name = XSTR (original, 0); | 
|  | file_location loc = get_md_ptr_loc (name)->loc; | 
|  | copy_md_ptr_loc (name + 1, name); | 
|  | name += 1; | 
|  | XSTR (original, 0) = name; | 
|  |  | 
|  | /* Build a copy of the name without the '<...>' attribute strings. | 
|  | Add the iterator associated with each such attribute string to ITERATORS | 
|  | and add an associated argument to TMP_ONAME.  */ | 
|  | char *copy = ASTRDUP (name); | 
|  | char *base = copy, *start, *end; | 
|  | overloaded_name tmp_oname; | 
|  | tmp_oname.arg_types.create (current_iterators.length ()); | 
|  | bool pending_underscore_p = false; | 
|  | while ((start = strchr (base, '<')) && (end = strchr (start, '>'))) | 
|  | { | 
|  | *end = 0; | 
|  | mapping *iterator; | 
|  | if (!map_attr_string (loc, start + 1, &iterator)) | 
|  | fatal_with_file_and_line ("unknown iterator `%s'", start + 1); | 
|  | *end = '>'; | 
|  |  | 
|  | /* Remove a trailing underscore, so that we don't end a name | 
|  | with "_" or turn "_<...>_" into "__".  */ | 
|  | if (start != base && start[-1] == '_') | 
|  | { | 
|  | start -= 1; | 
|  | pending_underscore_p = true; | 
|  | } | 
|  |  | 
|  | /* Add the text between either the last '>' or the start of | 
|  | the string and this '<'.  */ | 
|  | obstack_grow (&m_string_obstack, base, start - base); | 
|  | base = end + 1; | 
|  |  | 
|  | /* If there's a character we need to keep after the '>', check | 
|  | whether we should prefix it with a previously-dropped '_'.  */ | 
|  | if (base[0] != 0 && base[0] != '<') | 
|  | { | 
|  | if (pending_underscore_p && base[0] != '_') | 
|  | obstack_1grow (&m_string_obstack, '_'); | 
|  | pending_underscore_p = false; | 
|  | } | 
|  |  | 
|  | /* Skip define_subst iterators, since define_substs are allowed to | 
|  | add new match_operands in their output templates.  */ | 
|  | if (iterator->group != &substs) | 
|  | { | 
|  | /* Record an argument for ITERATOR.  */ | 
|  | iterators->safe_push (iterator); | 
|  | tmp_oname.arg_types.safe_push (iterator->group->type); | 
|  | } | 
|  | } | 
|  | if (base == copy) | 
|  | fatal_with_file_and_line ("no iterator attributes in name `%s'", name); | 
|  |  | 
|  | size_t length = obstack_object_size (&m_string_obstack); | 
|  | if (length == 0) | 
|  | fatal_with_file_and_line ("`%s' only contains iterator attributes", name); | 
|  |  | 
|  | /* Get the completed name.  */ | 
|  | obstack_grow (&m_string_obstack, base, strlen (base) + 1); | 
|  | char *new_name = XOBFINISH (&m_string_obstack, char *); | 
|  | tmp_oname.name = new_name; | 
|  |  | 
|  | if (!m_overloads_htab) | 
|  | m_overloads_htab = htab_create (31, overloaded_name_hash, | 
|  | overloaded_name_eq_p, NULL); | 
|  |  | 
|  | /* See whether another pattern had the same overload name and list | 
|  | of argument types.  Create a new permanent one if not.  */ | 
|  | void **slot = htab_find_slot (m_overloads_htab, &tmp_oname, INSERT); | 
|  | overloaded_name *oname = (overloaded_name *) *slot; | 
|  | if (!oname) | 
|  | { | 
|  | *slot = oname = new overloaded_name; | 
|  | oname->name = tmp_oname.name; | 
|  | oname->arg_types = tmp_oname.arg_types; | 
|  | oname->next = NULL; | 
|  | oname->first_instance = NULL; | 
|  | oname->next_instance_ptr = &oname->first_instance; | 
|  |  | 
|  | *m_next_overload_ptr = oname; | 
|  | m_next_overload_ptr = &oname->next; | 
|  | } | 
|  | else | 
|  | { | 
|  | obstack_free (&m_string_obstack, new_name); | 
|  | tmp_oname.arg_types.release (); | 
|  | } | 
|  |  | 
|  | return oname; | 
|  | } | 
|  |  | 
|  | /* Add an instance of ONAME for instruction pattern X.  ITERATORS[I] | 
|  | gives the iterator associated with argument I of ONAME.  */ | 
|  |  | 
|  | static void | 
|  | add_overload_instance (overloaded_name *oname, const vec<mapping *> &iterators, rtx x) | 
|  | { | 
|  | /* Create the instance.  */ | 
|  | overloaded_instance *instance = new overloaded_instance; | 
|  | instance->next = NULL; | 
|  | instance->arg_values.create (oname->arg_types.length ()); | 
|  | for (unsigned int i = 0; i < iterators.length (); ++i) | 
|  | { | 
|  | int value = iterators[i]->current_value->number; | 
|  | const char *name = iterators[i]->group->get_c_token (value); | 
|  | instance->arg_values.quick_push (name); | 
|  | } | 
|  | instance->name = XSTR (x, 0); | 
|  | instance->insn = x; | 
|  |  | 
|  | /* Chain it onto the end of ONAME's list.  */ | 
|  | *oname->next_instance_ptr = instance; | 
|  | oname->next_instance_ptr = &instance->next; | 
|  | } | 
|  |  | 
|  | /* Expand all iterators in the current rtx, which is given as ORIGINAL. | 
|  | Build a list of expanded rtxes in the EXPR_LIST pointed to by QUEUE.  */ | 
|  |  | 
|  | static void | 
|  | apply_iterators (rtx original, 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 (); | 
|  |  | 
|  | if (named_rtx_p (original) && XSTR (original, 0)[0] == '@') | 
|  | fatal_with_file_and_line ("'@' used without iterators"); | 
|  |  | 
|  | 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 ()); | 
|  |  | 
|  | /* Check whether this is a '@' overloaded pattern.  */ | 
|  | auto_vec<mapping *, 16> iterators; | 
|  | overloaded_name *oname | 
|  | = rtx_reader_ptr->handle_overloaded_name (original, &iterators); | 
|  |  | 
|  | for (;;) | 
|  | { | 
|  | /* Apply the current iterator values.  Accumulate a condition to | 
|  | 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.  */ | 
|  | bool add_oname = true; | 
|  | 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); | 
|  | /* Only handle '@' overloading for the default value. | 
|  | See handle_overloaded_name for details.  */ | 
|  | if (v != iuse->iterator->values) | 
|  | add_oname = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (oname && add_oname) | 
|  | add_overload_instance (oname, iterators, x); | 
|  |  | 
|  | /* 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.  */ | 
|  |  | 
|  | static struct mapping * | 
|  | add_mapping (struct iterator_group *group, htab_t table, const char *name) | 
|  | { | 
|  | struct mapping *m; | 
|  | void **slot; | 
|  |  | 
|  | m = XNEW (struct mapping); | 
|  | m->name = xstrdup (name); | 
|  | m->group = group; | 
|  | m->values = 0; | 
|  | m->current_value = NULL; | 
|  |  | 
|  | slot = htab_find_slot (table, m, INSERT); | 
|  | if (*slot != 0) | 
|  | fatal_with_file_and_line ("`%s' already defined", name); | 
|  |  | 
|  | *slot = m; | 
|  | return m; | 
|  | } | 
|  |  | 
|  | /* Add the pair (NUMBER, STRING) to a list of map_value structures. | 
|  | END_PTR points to the current null terminator for the list; return | 
|  | a pointer the new null terminator.  */ | 
|  |  | 
|  | static struct map_value ** | 
|  | add_map_value (struct map_value **end_ptr, int number, const char *string) | 
|  | { | 
|  | struct map_value *value; | 
|  |  | 
|  | value = XNEW (struct map_value); | 
|  | value->next = 0; | 
|  | value->number = number; | 
|  | value->string = string; | 
|  |  | 
|  | *end_ptr = value; | 
|  | return &value->next; | 
|  | } | 
|  |  | 
|  | /* Do one-time initialization of the mode and code attributes.  */ | 
|  |  | 
|  | static void | 
|  | initialize_iterators (void) | 
|  | { | 
|  | struct mapping *lower, *upper; | 
|  | struct map_value **lower_ptr, **upper_ptr; | 
|  | char *copy, *p; | 
|  | int i; | 
|  |  | 
|  | modes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); | 
|  | modes.iterators = htab_create (13, leading_string_hash, | 
|  | leading_string_eq_p, 0); | 
|  | modes.type = "machine_mode"; | 
|  | modes.find_builtin = find_mode; | 
|  | modes.apply_iterator = apply_mode_iterator; | 
|  | modes.get_c_token = get_mode_token; | 
|  |  | 
|  | codes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); | 
|  | codes.iterators = htab_create (13, leading_string_hash, | 
|  | leading_string_eq_p, 0); | 
|  | codes.type = "rtx_code"; | 
|  | codes.find_builtin = find_code; | 
|  | codes.apply_iterator = apply_code_iterator; | 
|  | codes.get_c_token = get_code_token; | 
|  |  | 
|  | ints.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); | 
|  | ints.iterators = htab_create (13, leading_string_hash, | 
|  | leading_string_eq_p, 0); | 
|  | ints.type = "int"; | 
|  | ints.find_builtin = find_int; | 
|  | ints.apply_iterator = apply_int_iterator; | 
|  | ints.get_c_token = get_int_token; | 
|  | ints.has_self_attr = true; | 
|  |  | 
|  | substs.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); | 
|  | substs.iterators = htab_create (13, leading_string_hash, | 
|  | leading_string_eq_p, 0); | 
|  | substs.type = "int"; | 
|  | substs.find_builtin = find_int; /* We don't use it, anyway.  */ | 
|  | #ifdef GENERATOR_FILE | 
|  | substs.apply_iterator = apply_subst_iterator; | 
|  | #endif | 
|  | substs.get_c_token = get_int_token; | 
|  |  | 
|  | lower = add_mapping (&modes, modes.attrs, "mode"); | 
|  | upper = add_mapping (&modes, modes.attrs, "MODE"); | 
|  | lower_ptr = &lower->values; | 
|  | upper_ptr = &upper->values; | 
|  | for (i = 0; i < MAX_MACHINE_MODE; i++) | 
|  | { | 
|  | copy = xstrdup (GET_MODE_NAME (i)); | 
|  | for (p = copy; *p != 0; p++) | 
|  | *p = TOLOWER (*p); | 
|  |  | 
|  | upper_ptr = add_map_value (upper_ptr, i, GET_MODE_NAME (i)); | 
|  | lower_ptr = add_map_value (lower_ptr, i, copy); | 
|  | } | 
|  |  | 
|  | lower = add_mapping (&codes, codes.attrs, "code"); | 
|  | upper = add_mapping (&codes, codes.attrs, "CODE"); | 
|  | lower_ptr = &lower->values; | 
|  | upper_ptr = &upper->values; | 
|  | for (i = 0; i < NUM_RTX_CODE; i++) | 
|  | { | 
|  | copy = xstrdup (GET_RTX_NAME (i)); | 
|  | for (p = copy; *p != 0; p++) | 
|  | *p = TOUPPER (*p); | 
|  |  | 
|  | lower_ptr = add_map_value (lower_ptr, i, GET_RTX_NAME (i)); | 
|  | upper_ptr = add_map_value (upper_ptr, i, copy); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #ifdef GENERATOR_FILE | 
|  | /* Process a define_conditions directive, starting with the optional | 
|  | space after the "define_conditions".  The directive looks like this: | 
|  |  | 
|  | (define_conditions [ | 
|  | (number "string") | 
|  | (number "string") | 
|  | ... | 
|  | ]) | 
|  |  | 
|  | It's not intended to appear in machine descriptions.  It is | 
|  | generated by (the program generated by) genconditions.cc, and | 
|  | slipped in at the beginning of the sequence of MD files read by | 
|  | most of the other generators.  */ | 
|  | void | 
|  | md_reader::read_conditions () | 
|  | { | 
|  | int c; | 
|  |  | 
|  | require_char_ws ('['); | 
|  |  | 
|  | while ( (c = read_skip_spaces ()) != ']') | 
|  | { | 
|  | struct md_name name; | 
|  | char *expr; | 
|  | int value; | 
|  |  | 
|  | if (c != '(') | 
|  | fatal_expected_char ('(', c); | 
|  |  | 
|  | read_name (&name); | 
|  | validate_const_int (name.string); | 
|  | value = atoi (name.string); | 
|  |  | 
|  | require_char_ws ('"'); | 
|  | expr = read_quoted_string (); | 
|  |  | 
|  | require_char_ws (')'); | 
|  |  | 
|  | add_c_test (expr, value); | 
|  | } | 
|  | } | 
|  | #endif /* #ifdef GENERATOR_FILE */ | 
|  |  | 
|  | static void | 
|  | validate_const_int (const char *string) | 
|  | { | 
|  | const char *cp; | 
|  | int valid = 1; | 
|  |  | 
|  | cp = string; | 
|  | while (*cp && ISSPACE (*cp)) | 
|  | cp++; | 
|  | if (*cp == '-' || *cp == '+') | 
|  | cp++; | 
|  | if (*cp == 0) | 
|  | valid = 0; | 
|  | for (; *cp; cp++) | 
|  | if (! ISDIGIT (*cp)) | 
|  | { | 
|  | valid = 0; | 
|  | break; | 
|  | } | 
|  | if (!valid) | 
|  | fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string); | 
|  | } | 
|  |  | 
|  | 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 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 at location LOC, where VALUE must | 
|  | match a built-in value from group GROUP.  If the use is in an operand | 
|  | of X, INDEX is the index of that operand, otherwise it is ignored.  */ | 
|  |  | 
|  | static void | 
|  | record_attribute_use (struct iterator_group *group, file_location loc, rtx x, | 
|  | unsigned int index, const char *value) | 
|  | { | 
|  | struct attribute_use ause = {group, loc, value, x, index}; | 
|  | attribute_uses.safe_push (ause); | 
|  | } | 
|  |  | 
|  | /* Interpret NAME as either a built-in value, iterator or attribute | 
|  | for group GROUP.  X and INDEX are the values to pass to GROUP's | 
|  | apply_iterator callback.  LOC is the location of the use.  */ | 
|  |  | 
|  | void | 
|  | md_reader::record_potential_iterator_use (struct iterator_group *group, | 
|  | file_location loc, | 
|  | rtx x, unsigned int index, | 
|  | const char *name) | 
|  | { | 
|  | struct mapping *m; | 
|  | size_t len; | 
|  |  | 
|  | 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, loc, 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>]) | 
|  |  | 
|  | from the MD file, where each <valuei> is either a bare symbol name or a | 
|  | "(<name> <string>)" pair.  The "(define..." part has already been read. | 
|  |  | 
|  | Represent the declaration as a "mapping" structure; add it to TABLE | 
|  | (which belongs to GROUP) and return it.  */ | 
|  |  | 
|  | struct mapping * | 
|  | md_reader::read_mapping (struct iterator_group *group, htab_t table) | 
|  | { | 
|  | struct md_name name; | 
|  | struct mapping *m; | 
|  | struct map_value **end_ptr; | 
|  | const char *string; | 
|  | int number, c; | 
|  |  | 
|  | /* Read the mapping name and create a structure for it.  */ | 
|  | read_name (&name); | 
|  | m = add_mapping (group, table, name.string); | 
|  |  | 
|  | require_char_ws ('['); | 
|  |  | 
|  | /* Read each value.  */ | 
|  | end_ptr = &m->values; | 
|  | c = read_skip_spaces (); | 
|  | do | 
|  | { | 
|  | if (c != '(') | 
|  | { | 
|  | /* A bare symbol name that is implicitly paired to an | 
|  | empty string.  */ | 
|  | unread_char (c); | 
|  | read_name (&name); | 
|  | string = ""; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* A "(name string)" pair.  */ | 
|  | read_name (&name); | 
|  | string = read_string (false); | 
|  | require_char_ws (')'); | 
|  | } | 
|  | auto *subm = (struct mapping *) htab_find (group->iterators, | 
|  | &name.string); | 
|  | if (subm) | 
|  | { | 
|  | if (m == subm) | 
|  | fatal_with_file_and_line ("recursive definition of `%s'", | 
|  | name.string); | 
|  | for (map_value *v = subm->values; v; v = v->next) | 
|  | { | 
|  | auto *joined = rtx_reader_ptr->join_c_conditions (v->string, | 
|  | string); | 
|  | end_ptr = add_map_value (end_ptr, v->number, joined); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | number = group->find_builtin (name.string); | 
|  | end_ptr = add_map_value (end_ptr, number, string); | 
|  | } | 
|  | c = read_skip_spaces (); | 
|  | } | 
|  | while (c != ']'); | 
|  |  | 
|  | 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, ""); | 
|  | 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]); | 
|  | add_map_value (end_ptr, 2, attr_operands[3]); | 
|  | } | 
|  |  | 
|  | /* Check newly-created code iterator ITERATOR to see whether every code has the | 
|  | same format.  */ | 
|  |  | 
|  | static void | 
|  | check_code_iterator (struct mapping *iterator) | 
|  | { | 
|  | struct map_value *v; | 
|  | enum rtx_code bellwether; | 
|  |  | 
|  | bellwether = (enum rtx_code) iterator->values->number; | 
|  | for (v = iterator->values->next; v != 0; v = v->next) | 
|  | if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0) | 
|  | fatal_with_file_and_line ("code iterator `%s' combines " | 
|  | "`%s' and `%s', which have different " | 
|  | "rtx formats", iterator->name, | 
|  | GET_RTX_NAME (bellwether), | 
|  | GET_RTX_NAME (v->number)); | 
|  | } | 
|  |  | 
|  | /* Check that all values of attribute ATTR are rtx codes that have a | 
|  | consistent format.  Return a representative code.  */ | 
|  |  | 
|  | static rtx_code | 
|  | check_attribute_codes (mapping *attr) | 
|  | { | 
|  | rtx_code bellwether = UNKNOWN; | 
|  | for (map_value *v = attr->values; v != 0; v = v->next) | 
|  | { | 
|  | rtx_code code = maybe_find_code (v->string); | 
|  | if (code == UNKNOWN) | 
|  | fatal_with_file_and_line ("attribute `%s' contains " | 
|  | "unrecognized rtx code `%s'", | 
|  | attr->name, v->string); | 
|  | if (bellwether == UNKNOWN) | 
|  | bellwether = code; | 
|  | else if (strcmp (GET_RTX_FORMAT (bellwether), | 
|  | GET_RTX_FORMAT (code)) != 0) | 
|  | fatal_with_file_and_line ("attribute `%s' combines " | 
|  | "`%s' and `%s', which have different " | 
|  | "rtx formats", attr->name, | 
|  | GET_RTX_NAME (bellwether), | 
|  | GET_RTX_NAME (code)); | 
|  | } | 
|  | return bellwether; | 
|  | } | 
|  |  | 
|  | /* Read an rtx-related declaration from the MD file, given that it | 
|  | starts with directive name RTX_NAME.  Return true if it expands to | 
|  | one or more rtxes (as defined by rtx.def).  When returning true, | 
|  | store the list of rtxes as an EXPR_LIST in *X.  */ | 
|  |  | 
|  | bool | 
|  | rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen) | 
|  | { | 
|  | /* Handle various rtx-related declarations that aren't themselves | 
|  | encoded as rtxes.  */ | 
|  | if (strcmp (rtx_name, "define_conditions") == 0) | 
|  | { | 
|  | read_conditions (); | 
|  | return false; | 
|  | } | 
|  | if (strcmp (rtx_name, "define_mode_attr") == 0) | 
|  | { | 
|  | read_mapping (&modes, modes.attrs); | 
|  | return false; | 
|  | } | 
|  | if (strcmp (rtx_name, "define_mode_iterator") == 0) | 
|  | { | 
|  | read_mapping (&modes, modes.iterators); | 
|  | return false; | 
|  | } | 
|  | if (strcmp (rtx_name, "define_code_attr") == 0) | 
|  | { | 
|  | read_mapping (&codes, codes.attrs); | 
|  | return false; | 
|  | } | 
|  | if (strcmp (rtx_name, "define_code_iterator") == 0) | 
|  | { | 
|  | 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); | 
|  |  | 
|  | /* 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.  */ | 
|  |  | 
|  | char * | 
|  | rtx_reader::read_until (const char *terminator_chars, bool consume_terminator) | 
|  | { | 
|  | int ch = read_skip_spaces (); | 
|  | unread_char (ch); | 
|  | auto_vec<char> buf; | 
|  | while (1) | 
|  | { | 
|  | ch = read_char (); | 
|  | if (strchr (terminator_chars, ch)) | 
|  | { | 
|  | if (!consume_terminator) | 
|  | unread_char (ch); | 
|  | break; | 
|  | } | 
|  | buf.safe_push (ch); | 
|  | } | 
|  | buf.safe_push ('\0'); | 
|  | return xstrdup (buf.address ()); | 
|  | } | 
|  |  | 
|  | /* Subroutine of read_rtx_code, for parsing zero or more flags.  */ | 
|  |  | 
|  | static void | 
|  | read_flags (rtx return_rtx) | 
|  | { | 
|  | while (1) | 
|  | { | 
|  | int ch = read_char (); | 
|  | if (ch != '/') | 
|  | { | 
|  | unread_char (ch); | 
|  | break; | 
|  | } | 
|  |  | 
|  | int flag_char = read_char (); | 
|  | switch (flag_char) | 
|  | { | 
|  | case 's': | 
|  | RTX_FLAG (return_rtx, in_struct) = 1; | 
|  | break; | 
|  | case 'v': | 
|  | RTX_FLAG (return_rtx, volatil) = 1; | 
|  | break; | 
|  | case 'u': | 
|  | RTX_FLAG (return_rtx, unchanging) = 1; | 
|  | break; | 
|  | case 'f': | 
|  | RTX_FLAG (return_rtx, frame_related) = 1; | 
|  | break; | 
|  | case 'j': | 
|  | RTX_FLAG (return_rtx, jump) = 1; | 
|  | break; | 
|  | case 'c': | 
|  | RTX_FLAG (return_rtx, call) = 1; | 
|  | break; | 
|  | case 'i': | 
|  | RTX_FLAG (return_rtx, return_val) = 1; | 
|  | break; | 
|  | default: | 
|  | fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING, | 
|  | or fail if STRING isn't recognized.  */ | 
|  |  | 
|  | static int | 
|  | parse_reg_note_name (const char *string) | 
|  | { | 
|  | for (int i = 0; i < REG_NOTE_MAX; i++) | 
|  | if (strcmp (string, GET_REG_NOTE_NAME (i)) == 0) | 
|  | return i; | 
|  | fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string); | 
|  | } | 
|  |  | 
|  | /* Allocate an rtx for code NAME.  If NAME is a code iterator or an | 
|  | attribute, record its use for later and use one of its possible | 
|  | values as an interim rtx code.  */ | 
|  |  | 
|  | rtx | 
|  | rtx_reader::rtx_alloc_for_name (const char *name) | 
|  | { | 
|  | #ifdef GENERATOR_FILE | 
|  | size_t len = strlen (name); | 
|  | if (name[0] == '<' && name[len - 1] == '>') | 
|  | { | 
|  | /* Copy the attribute string into permanent storage, without the | 
|  | angle brackets around it.  */ | 
|  | obstack *strings = get_string_obstack (); | 
|  | obstack_grow0 (strings, name + 1, len - 2); | 
|  | char *deferred_name = XOBFINISH (strings, char *); | 
|  |  | 
|  | /* Find the name of the attribute.  */ | 
|  | const char *attr = strchr (deferred_name, ':'); | 
|  | if (!attr) | 
|  | attr = deferred_name; | 
|  |  | 
|  | /* Find the attribute itself.  */ | 
|  | mapping *m = nullptr; | 
|  | for (auto attrs : { codes.attrs, ints.attrs, modes.attrs }) | 
|  | if (auto *newm = (mapping *) htab_find (attrs, &attr)) | 
|  | { | 
|  | if (m) | 
|  | fatal_with_file_and_line ("ambiguous attribute `%s`", attr); | 
|  | m = newm; | 
|  | } | 
|  | if (!m) | 
|  | fatal_with_file_and_line ("unknown attribute `%s'", attr); | 
|  |  | 
|  | /* Pick the first possible code for now, and record the attribute | 
|  | use for later.  */ | 
|  | rtx x = rtx_alloc (check_attribute_codes (m)); | 
|  | record_attribute_use (&codes, get_current_location (), | 
|  | x, 0, deferred_name); | 
|  | return x; | 
|  | } | 
|  |  | 
|  | mapping *iterator = (mapping *) htab_find (codes.iterators, &name); | 
|  | if (iterator != 0) | 
|  | { | 
|  | /* Pick the first possible code for now, and record the iterator | 
|  | use for later.  */ | 
|  | rtx x = rtx_alloc (rtx_code (iterator->values->number)); | 
|  | record_iterator_use (iterator, x, 0); | 
|  | return x; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return rtx_alloc (rtx_code (codes.find_builtin (name))); | 
|  | } | 
|  |  | 
|  | /* Subroutine of read_rtx and read_nested_rtx.  CODE_NAME is the name of | 
|  | either an rtx code or a code iterator.  Parse the rest of the rtx and | 
|  | return it.  */ | 
|  |  | 
|  | rtx | 
|  | rtx_reader::read_rtx_code (const char *code_name) | 
|  | { | 
|  | RTX_CODE code; | 
|  | const char *format_ptr; | 
|  | struct md_name name; | 
|  | rtx return_rtx; | 
|  | int c; | 
|  |  | 
|  | /* Linked list structure for making RTXs: */ | 
|  | struct rtx_list | 
|  | { | 
|  | struct rtx_list *next; | 
|  | rtx value;		/* Value of this node.  */ | 
|  | }; | 
|  |  | 
|  | #ifndef GENERATOR_FILE | 
|  | long reuse_id = -1; | 
|  | /* 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.  */ | 
|  | if (idx >= m_reuse_rtx_by_id.length ()) | 
|  | fatal_with_file_and_line ("invalid reuse index %u", idx); | 
|  | return_rtx = m_reuse_rtx_by_id[idx]; | 
|  | return return_rtx; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* Handle "const_double_zero".  */ | 
|  | if (strcmp (code_name, "const_double_zero") == 0) | 
|  | { | 
|  | code = CONST_DOUBLE; | 
|  | return_rtx = rtx_alloc (code); | 
|  | memset (return_rtx, 0, RTX_CODE_SIZE (code)); | 
|  | PUT_CODE (return_rtx, code); | 
|  | c = read_skip_spaces (); | 
|  | if (c == ':') | 
|  | { | 
|  | file_location loc = read_name (&name); | 
|  | record_potential_iterator_use (&modes, loc, return_rtx, 0, | 
|  | name.string); | 
|  | } | 
|  | else | 
|  | unread_char (c); | 
|  | return return_rtx; | 
|  | } | 
|  |  | 
|  | /* If we end up with an insn expression then we free this space below.  */ | 
|  | return_rtx = rtx_alloc_for_name (code_name); | 
|  | code = GET_CODE (return_rtx); | 
|  | format_ptr = GET_RTX_FORMAT (code); | 
|  | memset (return_rtx, 0, RTX_CODE_SIZE (code)); | 
|  | PUT_CODE (return_rtx, code); | 
|  |  | 
|  | #ifndef GENERATOR_FILE | 
|  | if (reuse_id != -1) | 
|  | { | 
|  | /* Store away for later reuse.  */ | 
|  | m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1, true); | 
|  | m_reuse_rtx_by_id[reuse_id] = return_rtx; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* 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.  */ | 
|  |  | 
|  | c = read_skip_spaces (); | 
|  | if (c == ':') | 
|  | { | 
|  | file_location loc = read_name (&name); | 
|  | record_potential_iterator_use (&modes, loc, return_rtx, 0, name.string); | 
|  | } | 
|  | else | 
|  | unread_char (c); | 
|  |  | 
|  | if (INSN_CHAIN_CODE_P (code)) | 
|  | { | 
|  | read_name (&name); | 
|  | INSN_UID (return_rtx) = atoi (name.string); | 
|  | } | 
|  |  | 
|  | /* 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); | 
|  | { | 
|  | 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; | 
|  |  | 
|  | switch (format_ptr[idx]) | 
|  | { | 
|  | /* 0 means a field for internal use only. | 
|  | Don't expect it to be present in the input.  */ | 
|  | case '0': | 
|  | if (code == REG) | 
|  | ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx); | 
|  | break; | 
|  |  | 
|  | case 'e': | 
|  | XEXP (return_rtx, idx) = read_nested_rtx (); | 
|  | break; | 
|  |  | 
|  | case 'u': | 
|  | XEXP (return_rtx, idx) = read_nested_rtx (); | 
|  | break; | 
|  |  | 
|  | case 'V': | 
|  | /* 'V' is an optional vector: if a closeparen follows, | 
|  | just store NULL for this element.  */ | 
|  | c = read_skip_spaces (); | 
|  | unread_char (c); | 
|  | if (c == ')') | 
|  | { | 
|  | XVEC (return_rtx, idx) = 0; | 
|  | break; | 
|  | } | 
|  | /* Now process the vector.  */ | 
|  | /* FALLTHRU */ | 
|  |  | 
|  | case 'E': | 
|  | { | 
|  | /* Obstack to store scratch vector in.  */ | 
|  | struct obstack vector_stack; | 
|  | int list_counter = 0; | 
|  | rtvec return_vec = NULL_RTVEC; | 
|  | rtx saved_rtx = NULL_RTX; | 
|  |  | 
|  | require_char_ws ('['); | 
|  |  | 
|  | /* Add expressions to a list, while keeping a count.  */ | 
|  | obstack_init (&vector_stack); | 
|  | while ((c = read_skip_spaces ()) && c != ']') | 
|  | { | 
|  | if (c == EOF) | 
|  | fatal_expected_char (']', c); | 
|  | unread_char (c); | 
|  |  | 
|  | rtx value; | 
|  | int repeat_count = 1; | 
|  | if (c == 'r') | 
|  | { | 
|  | /* Process "repeated xN" directive.  */ | 
|  | read_name (&name); | 
|  | if (strcmp (name.string, "repeated")) | 
|  | fatal_with_file_and_line ("invalid directive \"%s\"\n", | 
|  | name.string); | 
|  | read_name (&name); | 
|  | if (!sscanf (name.string, "x%d", &repeat_count)) | 
|  | fatal_with_file_and_line ("invalid repeat count \"%s\"\n", | 
|  | name.string); | 
|  |  | 
|  | /* We already saw one of the instances.  */ | 
|  | repeat_count--; | 
|  | value = saved_rtx; | 
|  | } | 
|  | else if (c == '(') | 
|  | value = read_nested_rtx (); | 
|  | else | 
|  | fatal_with_file_and_line ("unexpected character in vector"); | 
|  |  | 
|  | for (; repeat_count > 0; repeat_count--) | 
|  | { | 
|  | list_counter++; | 
|  | obstack_ptr_grow (&vector_stack, value); | 
|  | } | 
|  | saved_rtx = value; | 
|  | } | 
|  | if (list_counter > 0) | 
|  | { | 
|  | return_vec = rtvec_alloc (list_counter); | 
|  | memcpy (&return_vec->elem[0], obstack_finish (&vector_stack), | 
|  | list_counter * sizeof (rtx)); | 
|  | } | 
|  | else if (format_ptr[idx] == 'E') | 
|  | fatal_with_file_and_line ("vector must have at least one element"); | 
|  | XVEC (return_rtx, idx) = return_vec; | 
|  | obstack_free (&vector_stack, NULL); | 
|  | /* close bracket gotten */ | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 'S': | 
|  | case 'T': | 
|  | case 's': | 
|  | { | 
|  | char *stringbuf; | 
|  | int star_if_braced; | 
|  |  | 
|  | c = read_skip_spaces (); | 
|  | unread_char (c); | 
|  | if (c == ')') | 
|  | { | 
|  | /* 'S' fields are optional and should be NULL if no string | 
|  | was given.  Also allow normal 's' and 'T' strings to be | 
|  | omitted, treating them in the same way as empty strings.  */ | 
|  | XSTR (return_rtx, idx) = (format_ptr[idx] == 'S' ? NULL : ""); | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* The output template slot of a DEFINE_INSN, DEFINE_INSN_AND_SPLIT, | 
|  | DEFINE_INSN_AND_REWRITE or DEFINE_PEEPHOLE automatically | 
|  | gets a star inserted as its first character, if it is | 
|  | written with a brace block instead of a string constant.  */ | 
|  | star_if_braced = (format_ptr[idx] == 'T'); | 
|  |  | 
|  | stringbuf = read_string (star_if_braced); | 
|  | if (!stringbuf) | 
|  | break; | 
|  |  | 
|  | #ifdef GENERATOR_FILE | 
|  | /* For insn patterns, we want to provide a default name | 
|  | based on the file and line, like "*foo.md:12", if the | 
|  | given name is blank.  These are only for define_insn and | 
|  | define_insn_and_split, to aid debugging.  */ | 
|  | if (*stringbuf == '\0' | 
|  | && idx == 0 | 
|  | && (GET_CODE (return_rtx) == DEFINE_INSN | 
|  | || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT | 
|  | || GET_CODE (return_rtx) == DEFINE_INSN_AND_REWRITE)) | 
|  | { | 
|  | const char *old_stringbuf = stringbuf; | 
|  | struct obstack *string_obstack = get_string_obstack (); | 
|  | char line_name[20]; | 
|  | const char *read_md_filename = get_filename (); | 
|  | const char *fn = (read_md_filename ? read_md_filename : "rtx"); | 
|  | const char *slash; | 
|  | for (slash = fn; *slash; slash ++) | 
|  | if (*slash == '/' || *slash == '\\' || *slash == ':') | 
|  | fn = slash + 1; | 
|  | obstack_1grow (string_obstack, '*'); | 
|  | obstack_grow (string_obstack, fn, strlen (fn)); | 
|  | sprintf (line_name, ":%d", get_lineno ()); | 
|  | obstack_grow (string_obstack, line_name, strlen (line_name)+1); | 
|  | stringbuf = XOBFINISH (string_obstack, char *); | 
|  | copy_md_ptr_loc (stringbuf, old_stringbuf); | 
|  | } | 
|  |  | 
|  | /* Find attr-names in the string.  */ | 
|  | char *str; | 
|  | char *start, *end, *ptr; | 
|  | char tmpstr[256]; | 
|  | ptr = &tmpstr[0]; | 
|  | end = stringbuf; | 
|  | while ((start = strchr (end, '<')) && (end  = strchr (start, '>'))) | 
|  | { | 
|  | if ((end - start - 1 > 0) | 
|  | && (end - start - 1 < (int)sizeof (tmpstr))) | 
|  | { | 
|  | strncpy (tmpstr, start+1, end-start-1); | 
|  | tmpstr[end-start-1] = 0; | 
|  | end++; | 
|  | } | 
|  | else | 
|  | break; | 
|  | struct mapping *m | 
|  | = (struct mapping *) htab_find (substs.attrs, &ptr); | 
|  | if (m != 0) | 
|  | { | 
|  | /* Here we should find linked subst-iter.  */ | 
|  | str = find_subst_iter_by_attr (ptr); | 
|  | if (str) | 
|  | m = (struct mapping *) htab_find (substs.iterators, &str); | 
|  | else | 
|  | m = 0; | 
|  | } | 
|  | if (m != 0) | 
|  | record_iterator_use (m, return_rtx, 0); | 
|  | } | 
|  | #endif /* #ifdef GENERATOR_FILE */ | 
|  |  | 
|  | const char *string_ptr = finalize_string (stringbuf); | 
|  |  | 
|  | if (star_if_braced) | 
|  | XTMPL (return_rtx, idx) = string_ptr; | 
|  | else | 
|  | XSTR (return_rtx, idx) = string_ptr; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 'i': | 
|  | case 'n': | 
|  | case 'w': | 
|  | case 'p': | 
|  | case 'L': | 
|  | { | 
|  | /* Can be an iterator or an integer constant.  */ | 
|  | file_location loc = read_name (&name); | 
|  | record_potential_iterator_use (&ints, loc, return_rtx, idx, | 
|  | name.string); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case 'r': | 
|  | read_name (&name); | 
|  | validate_const_int (name.string); | 
|  | set_regno_raw (return_rtx, atoi (name.string), 1); | 
|  | REG_ATTRS (return_rtx) = NULL; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  |  | 
|  | return return_rtx; | 
|  | } | 
|  |  | 
|  | /* Read a nested rtx construct from the MD file and return it.  */ | 
|  |  | 
|  | rtx | 
|  | rtx_reader::read_nested_rtx () | 
|  | { | 
|  | struct md_name name; | 
|  | rtx return_rtx; | 
|  |  | 
|  | /* 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); | 
|  |  | 
|  | require_char_ws (')'); | 
|  |  | 
|  | return_rtx = postprocess (return_rtx); | 
|  |  | 
|  | return return_rtx; | 
|  | } | 
|  |  | 
|  | /* Mutually recursive subroutine of read_rtx which reads | 
|  | (thing x1 x2 x3 ...) and produces RTL as if | 
|  | (thing x1 (thing x2 (thing x3 ...)))  had been written. | 
|  | 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.  */ | 
|  | rtx | 
|  | rtx_reader::read_rtx_variadic (rtx form) | 
|  | { | 
|  | char c = '('; | 
|  | rtx p = form, q; | 
|  |  | 
|  | do | 
|  | { | 
|  | unread_char (c); | 
|  |  | 
|  | q = rtx_alloc (GET_CODE (p)); | 
|  | PUT_MODE (q, GET_MODE (p)); | 
|  |  | 
|  | XEXP (q, 0) = XEXP (p, 1); | 
|  | XEXP (q, 1) = read_nested_rtx (); | 
|  |  | 
|  | XEXP (p, 1) = q; | 
|  | p = q; | 
|  | c = read_skip_spaces (); | 
|  | } | 
|  | while (c == '('); | 
|  | 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; | 
|  | } |