From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/read-rtl.c | 1140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1140 insertions(+) create mode 100644 gcc/read-rtl.c (limited to 'gcc/read-rtl.c') diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c new file mode 100644 index 000000000..1402c5468 --- /dev/null +++ b/gcc/read-rtl.c @@ -0,0 +1,1140 @@ +/* RTL reader for GCC. + Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2007, 2008, 2010 + Free Software Foundation, Inc. + +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 +. */ + +#include "bconfig.h" + +/* 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 "hashtab.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 mode or code 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; + + /* 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; +}; + +/* A structure for abstracting the common parts of code and mode iterators. */ +struct iterator_group { + /* 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 + return its integer value. */ + int (*find_builtin) (const char *); + + /* Return true if the given rtx uses the given mode or code. */ + bool (*uses_iterator_p) (rtx, int); + + /* Make the given rtx use the given mode or code. */ + void (*apply_iterator) (rtx, int); +}; + +/* 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; +}; + +/* 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); +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); + +/* 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; + +/* Implementations of the iterator_group callbacks for modes. */ + +static 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 bool +uses_mode_iterator_p (rtx x, int mode) +{ + return (int) GET_MODE (x) == mode; +} + +static void +apply_mode_iterator (rtx x, int mode) +{ + PUT_MODE (x, (enum machine_mode) mode); +} + +/* Implementations of the iterator_group callbacks for codes. */ + +static int +find_code (const char *name) +{ + int i; + + for (i = 0; i < NUM_RTX_CODE; i++) + if (strcmp (GET_RTX_NAME (i), name) == 0) + return i; + + fatal_with_file_and_line ("unknown rtx code `%s'", name); +} + +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) +{ + PUT_CODE (x, (enum rtx_code) code); +} + +/* Map a code or mode attribute string P to the underlying string for + ITERATOR and VALUE. */ + +static struct map_value * +map_attr_string (const char *p, struct mapping *iterator, int value) +{ + const char *attr; + struct mapping *m; + struct map_value *v; + + /* If there's a "iterator:" prefix, check whether the iterator name matches. + Set ATTR to the start of the attribute name. */ + attr = strchr (p, ':'); + if (attr == 0) + attr = p; + else + { + if (strncmp (p, iterator->name, attr - p) != 0 + || iterator->name[attr - p] != 0) + return 0; + 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) + { + if (pm->number == indx) + { + struct map_value *v; + + v = map_attr_string (pm->string, iterator, value); + if (v) + PUT_MODE (x, (enum machine_mode) find_mode (v->string)); + else + *unknown = pm->string; + return; + } + } +} + +/* Given that ITERATOR is being expanded as VALUE, apply the appropriate + string substitutions to STRING. Return the new string if any changes + were needed, otherwise return STRING itself. */ + +static const char * +apply_iterator_to_string (const char *string, struct mapping *iterator, int value) +{ + char *base, *copy, *p, *start, *end; + struct map_value *v; + + if (string == 0) + return string; + + base = p = copy = ASTRDUP (string); + while ((start = strchr (p, '<')) && (end = strchr (start, '>'))) + { + p = start + 1; + + *end = 0; + v = map_attr_string (p, iterator, value); + *end = '>'; + if (v == 0) + continue; + + /* Add everything between the last copied byte and the '<', + then add in the attribute value. */ + obstack_grow (&string_obstack, base, start - base); + obstack_grow (&string_obstack, v->string, strlen (v->string)); + base = end + 1; + } + if (base != copy) + { + obstack_grow (&string_obstack, base, strlen (base) + 1); + copy = XOBFINISH (&string_obstack, char *); + copy_md_ptr_loc (copy, string); + return copy; + } + return string; +} + +/* Return a copy of ORIGINAL in which all uses of ITERATOR have been + replaced by VALUE. MODE_MAPS holds information about attribute + strings used for modes. This sets *UNKNOWN_MODE_ATTR to the value of + an unknown mode attribute, and does not change it otherwise. */ + +static rtx +apply_iterator_to_rtx (rtx original, struct mapping *iterator, int value, + struct map_value *mode_maps, + const char **unknown_mode_attr) +{ + 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); + + /* Change each string and recursively change each rtx. */ + format_ptr = GET_RTX_FORMAT (bellwether_code); + 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); + break; + + case 'S': + case 's': + XSTR (x, i) = apply_iterator_to_string (XSTR (x, i), iterator, value); + break; + + case 'e': + XEXP (x, i) = apply_iterator_to_rtx (XEXP (x, i), iterator, value, + mode_maps, unknown_mode_attr); + 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) = apply_iterator_to_rtx (XVECEXP (original, i, j), + iterator, value, mode_maps, + unknown_mode_attr); + } + break; + + default: + break; + } + 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". */ + +static const char * +add_condition_to_string (const char *original, const char *extra) +{ + if (original != 0 && original[0] == '&' && original[1] == '&') + return original; + return join_c_conditions (original, extra); +} + +/* 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: + 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: + 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; + } +} + +/* 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. */ + +static int +apply_iterator_traverse (void **slot, void *data) +{ + struct iterator_traverse_data *mtd = (struct iterator_traverse_data *) data; + struct mapping *iterator; + struct map_value *v; + rtx elem, new_elem, original, x; + + iterator = (struct mapping *) *slot; + for (elem = mtd->queue; elem != 0; elem = XEXP (elem, 1)) + if (uses_iterator_p (XEXP (elem, 0), iterator)) + { + /* For each iterator we expand, we set UNKNOWN_MODE_ATTR to NULL. + If apply_iterator_rtx finds an unknown attribute for a mode, + it will set it to the attribute. We want to know whether + the attribute is unknown after we have expanded all + possible iterators, so setting it to NULL here gives us the + right result when the hash table traversal is complete. */ + mtd->unknown_mode_attr = NULL; + + original = XEXP (elem, 0); + for (v = iterator->values; v != 0; v = v->next) + { + x = apply_iterator_to_rtx (original, iterator, v->number, + mtd->mode_maps, + &mtd->unknown_mode_attr); + add_condition_to_rtx (x, v->string); + if (v != iterator->values) + { + /* Insert a new EXPR_LIST node after ELEM and put the + new expansion there. */ + new_elem = rtx_alloc (EXPR_LIST); + XEXP (new_elem, 1) = XEXP (elem, 1); + XEXP (elem, 1) = new_elem; + elem = new_elem; + } + XEXP (elem, 0) = x; + } + } + return 1; +} + +/* Add a new "mapping" structure to hashtable TABLE. NAME is the name + of the mapping and GROUP is the group to which it belongs. */ + +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->index = htab_elements (table); + m->values = 0; + + 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.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"); + 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); + } +} + +/* Provide a version of a function to read a long long if the system does + not provide one. */ +#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ) +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 = (~(unsigned HOST_WIDE_INT) 0) >> 1; + break; + } + tmp_wide = new_wide; + p++; + } + + if (neg) + tmp_wide = -tmp_wide; + return tmp_wide; +} +#endif + +/* 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.c, and + slipped in at the beginning of the sequence of MD files read by + most of the other generators. */ +static void +read_conditions (void) +{ + int c; + + c = read_skip_spaces (); + if (c != '[') + fatal_expected_char ('[', c); + + 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); + + c = read_skip_spaces (); + if (c != '"') + fatal_expected_char ('"', c); + expr = read_quoted_string (); + + c = read_skip_spaces (); + if (c != ')') + fatal_expected_char (')', c); + + add_c_test (expr, value); + } +} + +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; + if (!valid) + fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string); +} + +/* Search GROUP for a mode or code called NAME and return its numerical + identifier. */ + +static int +find_iterator (struct iterator_group *group, const char *name) +{ + struct mapping *m; + + m = (struct mapping *) htab_find (group->iterators, &name); + if (m != 0) + return m->index + group->num_builtins; + return group->find_builtin (name); +} + +/* Finish reading a declaration of the form: + + (define... [ ... ]) + + from the MD file, where each is either a bare symbol name or a + "( )" 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. */ + +static struct mapping * +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); + + c = read_skip_spaces (); + if (c != '[') + fatal_expected_char ('[', c); + + /* 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); + c = read_skip_spaces (); + if (c != ')') + fatal_expected_char (')', c); + } + number = group->find_builtin (name.string); + end_ptr = add_map_value (end_ptr, number, string); + c = read_skip_spaces (); + } + while (c != ']'); + + return m; +} + +/* Check newly-created code iterator ITERATOR to see whether every code has the + same format. Initialize the iterator's entry in bellwether_codes. */ + +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 " + "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 + 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 +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) + { + initialize_iterators (); + queue_head = rtx_alloc (EXPR_LIST); + } + + /* Handle various rtx-related declarations that aren't themselves + encoded as rtxes. */ + if (strcmp (rtx_name, "define_conditions") == 0) + { + 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; + } + + 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); + + *x = queue_head; + return true; +} + +/* 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. */ + +static rtx +read_rtx_code (const char *code_name, struct map_value **mode_maps) +{ + int i; + RTX_CODE real_code, bellwether_code; + const char *format_ptr; + struct md_name name; + rtx return_rtx; + int c; + int tmp_int; + HOST_WIDE_INT tmp_wide; + + /* Linked list structure for making RTXs: */ + struct rtx_list + { + struct rtx_list *next; + rtx value; /* Value of this node. */ + }; + + real_code = (enum rtx_code) find_iterator (&codes, code_name); + bellwether_code = BELLWETHER_CODE (real_code); + + /* 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); + + /* If what follows is `: mode ', read it and + store the mode in the rtx. */ + + 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"); + } + else + unread_char (i); + + for (i = 0; format_ptr[i] != 0; i++) + switch (format_ptr[i]) + { + /* 0 means a field for internal use only. + Don't expect it to be present in the input. */ + case '0': + break; + + case 'e': + case 'u': + XEXP (return_rtx, i) = read_nested_rtx (mode_maps); + break; + + case 'V': + /* 'V' is an optional vector: if a closeparen follows, + just store NULL for this element. */ + c = read_skip_spaces (); + unread_char (c); + if (c == ')') + { + XVEC (return_rtx, i) = 0; + break; + } + /* Now process the vector. */ + + case 'E': + { + /* Obstack to store scratch vector in. */ + struct obstack vector_stack; + int list_counter = 0; + rtvec return_vec = NULL_RTVEC; + + c = read_skip_spaces (); + if (c != '[') + fatal_expected_char ('[', c); + + /* Add expressions to a list, while keeping a count. */ + obstack_init (&vector_stack); + while ((c = read_skip_spaces ()) && c != ']') + { + if (c == EOF) + fatal_expected_char (']', c); + unread_char (c); + list_counter++; + obstack_ptr_grow (&vector_stack, read_nested_rtx (mode_maps)); + } + if (list_counter > 0) + { + return_vec = rtvec_alloc (list_counter); + memcpy (&return_vec->elem[0], obstack_finish (&vector_stack), + list_counter * sizeof (rtx)); + } + else if (format_ptr[i] == 'E') + fatal_with_file_and_line ("vector must have at least one element"); + XVEC (return_rtx, i) = return_vec; + obstack_free (&vector_stack, NULL); + /* close bracket gotten */ + } + break; + + case 'S': + case 'T': + case 's': + { + char *stringbuf; + int star_if_braced; + + c = read_skip_spaces (); + unread_char (c); + if (c == ')') + { + /* 'S' fields are optional and should be NULL if no string + was given. Also allow normal 's' and 'T' strings to be + omitted, treating them in the same way as empty strings. */ + XSTR (return_rtx, i) = (format_ptr[i] == 'S' ? NULL : ""); + break; + } + + /* The output template slot of a DEFINE_INSN, + DEFINE_INSN_AND_SPLIT, or DEFINE_PEEPHOLE automatically + gets a star inserted as its first character, if it is + written with a brace block instead of a string constant. */ + star_if_braced = (format_ptr[i] == 'T'); + + stringbuf = read_string (star_if_braced); + + /* For insn patterns, we want to provide a default name + based on the file and line, like "*foo.md:12", if the + given name is blank. These are only for define_insn and + define_insn_and_split, to aid debugging. */ + if (*stringbuf == '\0' + && i == 0 + && (GET_CODE (return_rtx) == DEFINE_INSN + || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT)) + { + char line_name[20]; + const char *fn = (read_md_filename ? read_md_filename : "rtx"); + const char *slash; + for (slash = fn; *slash; slash ++) + if (*slash == '/' || *slash == '\\' || *slash == ':') + fn = slash + 1; + obstack_1grow (&string_obstack, '*'); + obstack_grow (&string_obstack, fn, strlen (fn)); + sprintf (line_name, ":%d", read_md_lineno); + obstack_grow (&string_obstack, line_name, strlen (line_name)+1); + stringbuf = XOBFINISH (&string_obstack, char *); + } + + if (star_if_braced) + XTMPL (return_rtx, i) = stringbuf; + else + XSTR (return_rtx, i) = stringbuf; + } + break; + + case 'w': + read_name (&name); + validate_const_int (name.string); +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + tmp_wide = atoi (name.string); +#else +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG + tmp_wide = atol (name.string); +#else + /* Prefer atoll over atoq, since the former is in the ISO C99 standard. + But prefer not to use our hand-rolled function above either. */ +#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ) + tmp_wide = atoll (name.string); +#else + tmp_wide = atoq (name.string); +#endif +#endif +#endif + XWINT (return_rtx, i) = tmp_wide; + break; + + case 'i': + case 'n': + read_name (&name); + validate_const_int (name.string); + tmp_int = atoi (name.string); + XINT (return_rtx, i) = tmp_int; + break; + + default: + gcc_unreachable (); + } + + c = read_skip_spaces (); + /* Syntactic sugar for AND and IOR, allowing Lisp-like + arbitrary number of arguments for them. */ + if (c == '(' + && (GET_CODE (return_rtx) == AND + || GET_CODE (return_rtx) == IOR)) + return read_rtx_variadic (mode_maps, return_rtx); + + 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. */ + +static rtx +read_nested_rtx (struct map_value **mode_maps) +{ + struct md_name name; + int c; + rtx return_rtx; + + c = read_skip_spaces (); + if (c != '(') + fatal_expected_char ('(', c); + + read_name (&name); + if (strcmp (name.string, "nil") == 0) + return_rtx = NULL; + else + return_rtx = read_rtx_code (name.string, mode_maps); + + c = read_skip_spaces (); + if (c != ')') + fatal_expected_char (')', c); + + 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. */ +static rtx +read_rtx_variadic (struct map_value **mode_maps, 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 (mode_maps); + + XEXP (p, 1) = q; + p = q; + c = read_skip_spaces (); + } + while (c == '('); + unread_char (c); + return form; +} -- cgit v1.2.3