X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fread-rtl.c;h=1402c5468371c0a90fbf63b59c65bca6bd2dbade;hp=377eb7e051e470ab4b3a48650603f14d5ceee845;hb=15c581919d5e1aa94eb0023c17d25497dee0caaf;hpb=aab2cf92f98dc58ac1bffb472b685b9b73f71529 diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c index 377eb7e051e..1402c546837 100644 --- a/gcc/read-rtl.c +++ b/gcc/read-rtl.c @@ -1,13 +1,13 @@ /* RTL reader for GCC. Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002, - 2003 + 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 2, or (at your option) any later +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 @@ -16,345 +16,596 @@ 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 COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +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 htab_t md_constants; - -static void fatal_with_file_and_line (FILE *, const char *, ...) - ATTRIBUTE_PRINTF_2 ATTRIBUTE_NORETURN; -static void fatal_expected_char (FILE *, int, int) ATTRIBUTE_NORETURN; -static void read_name (char *, FILE *); -static char *read_string (struct obstack *, FILE *, int); -static char *read_quoted_string (struct obstack *, FILE *); -static char *read_braced_string (struct obstack *, FILE *); -static void read_escape (struct obstack *, FILE *); -static hashval_t def_hash (const void *); -static int def_name_eq_p (const void *, const void *); -static void read_constants (FILE *infile, char *tmp_char); -static void validate_const_int (FILE *, const char *); +static int +find_mode (const char *name) +{ + int i; -/* Subroutines of read_rtx. */ + for (i = 0; i < NUM_MACHINE_MODES; i++) + if (strcmp (GET_MODE_NAME (i), name) == 0) + return i; -/* The current line number for the file. */ -int read_rtx_lineno = 1; + fatal_with_file_and_line ("unknown mode `%s'", name); +} -/* The filename for aborting with file and line. */ -const char *read_rtx_filename = ""; +static bool +uses_mode_iterator_p (rtx x, int mode) +{ + return (int) GET_MODE (x) == mode; +} static void -fatal_with_file_and_line (FILE *infile, const char *msg, ...) +apply_mode_iterator (rtx x, int mode) { - char context[64]; - size_t i; - int c; - va_list ap; - - va_start (ap, msg); + PUT_MODE (x, (enum machine_mode) mode); +} - fprintf (stderr, "%s:%d: ", read_rtx_filename, read_rtx_lineno); - vfprintf (stderr, msg, ap); - putc ('\n', stderr); +/* Implementations of the iterator_group callbacks for codes. */ - /* Gather some following context. */ - for (i = 0; i < sizeof (context)-1; ++i) - { - c = getc (infile); - if (c == EOF) - break; - if (c == '\r' || c == '\n') - break; - context[i] = c; - } - context[i] = '\0'; +static int +find_code (const char *name) +{ + int i; - fprintf (stderr, "%s:%d: following context is `%s'\n", - read_rtx_filename, read_rtx_lineno, context); + for (i = 0; i < NUM_RTX_CODE; i++) + if (strcmp (GET_RTX_NAME (i), name) == 0) + return i; - va_end (ap); - exit (1); + fatal_with_file_and_line ("unknown rtx code `%s'", name); } -/* Dump code after printing a message. Used when read_rtx finds - invalid data. */ +static bool +uses_code_iterator_p (rtx x, int code) +{ + return (int) GET_CODE (x) == code; +} static void -fatal_expected_char (FILE *infile, int expected_c, int actual_c) +apply_code_iterator (rtx x, int code) { - fatal_with_file_and_line (infile, "expected character `%c', found `%c'", - expected_c, actual_c); + PUT_CODE (x, (enum rtx_code) code); } -/* Read chars from INFILE until a non-whitespace char - and return that. Comments, both Lisp style and C style, - are treated as whitespace. - Tools such as genflags use this function. */ +/* Map a code or mode attribute string P to the underlying string for + ITERATOR and VALUE. */ -int -read_skip_spaces (FILE *infile) +static struct map_value * +map_attr_string (const char *p, struct mapping *iterator, int value) { - int c; - - while (1) + 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 { - c = getc (infile); - switch (c) - { - case '\n': - read_rtx_lineno++; - break; + if (strncmp (p, iterator->name, attr - p) != 0 + || iterator->name[attr - p] != 0) + return 0; + attr++; + } - case ' ': case '\t': case '\f': case '\r': - break; + /* Find the attribute specification. */ + m = (struct mapping *) htab_find (iterator->group->attrs, &attr); + if (m == 0) + return 0; - case ';': - do - c = getc (infile); - while (c != '\n' && c != EOF); - read_rtx_lineno++; - break; + /* Find the attribute value for VALUE. */ + for (v = m->values; v != 0; v = v->next) + if (v->number == value) + break; - case '/': - { - int prevc; - c = getc (infile); - if (c != '*') - fatal_expected_char (infile, '*', c); + return v; +} - prevc = 0; - while ((c = getc (infile)) && c != EOF) - { - if (c == '\n') - read_rtx_lineno++; - else if (prevc == '*' && c == '/') - break; - prevc = c; - } - } - break; +/* 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. */ - default: - return c; - } - } +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; } -/* Read an rtx code name into the buffer STR[]. - It is terminated by any of the punctuation chars of rtx printed syntax. */ +/* 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 -read_name (char *str, FILE *infile) +apply_mode_maps (rtx x, struct map_value *mode_maps, struct mapping *iterator, + int value, const char **unknown) { - char *p; - int c; + unsigned int offset; + int indx; + struct map_value *pm; - c = read_skip_spaces (infile); + offset = MAX_MACHINE_MODE + htab_elements (modes.iterators); + if (GET_MODE (x) < offset) + return; - p = str; - while (1) + indx = GET_MODE (x) - offset; + for (pm = mode_maps; pm; pm = pm->next) { - if (c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r') - break; - if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/' - || c == '(' || c == '[') + if (pm->number == indx) { - ungetc (c, infile); - break; + 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; } - *p++ = c; - c = getc (infile); } - if (p == str) - fatal_with_file_and_line (infile, "missing name or number"); - if (c == '\n') - read_rtx_lineno++; +} - *p = 0; +/* 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. */ - if (md_constants) - { - /* Do constant expansion. */ - struct md_constant *def; +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; - p = str; - do - { - struct md_constant tmp_def; - - tmp_def.name = p; - def = htab_find (md_constants, &tmp_def); - if (def) - p = def->value; - } while (def); - if (p != str) - strcpy (str, p); + 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; } -/* Subroutine of the string readers. Handles backslash escapes. - Caller has read the backslash, but not placed it into the obstack. */ -static void -read_escape (struct obstack *ob, FILE *infile) +/* 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) { - int c = getc (infile); + struct iterator_group *group; + const char *format_ptr; + int i, j; + + if (x == 0) + return false; - switch (c) + 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)) { - /* Backslash-newline is replaced by nothing, as in C. */ - case '\n': - read_rtx_lineno++; - return; - - /* \" \' \\ are replaced by the second character. */ - case '\\': - case '"': - case '\'': + case DEFINE_INSN: + case DEFINE_EXPAND: + XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); break; - /* Standard C string escapes: - \a \b \f \n \r \t \v - \[0-7] \x - all are passed through to the output string unmolested. - In normal use these wind up in a string constant processed - by the C compiler, which will translate them appropriately. - We do not bother checking that \[0-7] are followed by up to - two octal digits, or that \x is followed by N hex digits. - \? \u \U are left out because they are not in traditional C. */ - case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v': - case '0': case '1': case '2': case '3': case '4': case '5': case '6': - case '7': case 'x': - obstack_1grow (ob, '\\'); + 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; - /* \; makes stuff for a C string constant containing - newline and tab. */ - case ';': - obstack_grow (ob, "\\n\\t", 4); - return; + 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; - /* pass anything else through, but issue a warning. */ default: - fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n", - read_rtx_filename, read_rtx_lineno, c); - obstack_1grow (ob, '\\'); break; } +} - obstack_1grow (ob, c); +/* 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. */ -/* Read a double-quoted string onto the obstack. Caller has scanned - the leading quote. */ -static char * -read_quoted_string (struct obstack *ob, FILE *infile) +static struct mapping * +add_mapping (struct iterator_group *group, htab_t table, const char *name) { - int c; + struct mapping *m; + void **slot; - while (1) - { - c = getc (infile); /* Read the string */ - if (c == '\n') - read_rtx_lineno++; - else if (c == '\\') - { - read_escape (ob, infile); - continue; - } - else if (c == '"') - break; + m = XNEW (struct mapping); + m->name = xstrdup (name); + m->group = group; + m->index = htab_elements (table); + m->values = 0; - obstack_1grow (ob, c); - } + slot = htab_find_slot (table, m, INSERT); + if (*slot != 0) + fatal_with_file_and_line ("`%s' already defined", name); - obstack_1grow (ob, 0); - return obstack_finish (ob); + *slot = m; + return m; } -/* Read a braced string (a la Tcl) onto the obstack. Caller has - scanned the leading brace. Note that unlike quoted strings, - the outermost braces _are_ included in the string constant. */ -static char * -read_braced_string (struct obstack *ob, FILE *infile) -{ - int c; - int brace_depth = 1; /* caller-processed */ - unsigned long starting_read_rtx_lineno = read_rtx_lineno; +/* 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. */ - obstack_1grow (ob, '{'); - while (brace_depth) - { - c = getc (infile); /* Read the string */ - - if (c == '\n') - read_rtx_lineno++; - else if (c == '{') - brace_depth++; - else if (c == '}') - brace_depth--; - else if (c == '\\') - { - read_escape (ob, infile); - continue; - } - else if (c == EOF) - fatal_with_file_and_line - (infile, "missing closing } for opening brace on line %lu", - starting_read_rtx_lineno); +static struct map_value ** +add_map_value (struct map_value **end_ptr, int number, const char *string) +{ + struct map_value *value; - obstack_1grow (ob, c); - } + value = XNEW (struct map_value); + value->next = 0; + value->number = number; + value->string = string; - obstack_1grow (ob, 0); - return obstack_finish (ob); + *end_ptr = value; + return &value->next; } -/* Read some kind of string constant. This is the high-level routine - used by read_rtx. It handles surrounding parentheses, leading star, - and dispatch to the appropriate string constant reader. */ +/* Do one-time initialization of the mode and code attributes. */ -static char * -read_string (struct obstack *ob, FILE *infile, int star_if_braced) +static void +initialize_iterators (void) { - char *stringbuf; - int saw_paren = 0; - int c; - - c = read_skip_spaces (infile); - if (c == '(') + 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++) { - saw_paren = 1; - c = read_skip_spaces (infile); - } + copy = xstrdup (GET_MODE_NAME (i)); + for (p = copy; *p != 0; p++) + *p = TOLOWER (*p); - if (c == '"') - stringbuf = read_quoted_string (ob, infile); - else if (c == '{') - { - if (star_if_braced) - obstack_1grow (ob, '*'); - stringbuf = read_braced_string (ob, infile); + upper_ptr = add_map_value (upper_ptr, i, GET_MODE_NAME (i)); + lower_ptr = add_map_value (lower_ptr, i, copy); } - else - fatal_with_file_and_line (infile, "expected `\"' or `{', found `%c'", c); - if (saw_paren) + 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++) { - c = read_skip_spaces (infile); - if (c != ')') - fatal_expected_char (infile, ')', c); - } + copy = xstrdup (GET_RTX_NAME (i)); + for (p = copy; *p != 0; p++) + *p = TOUPPER (*p); - return stringbuf; + 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 @@ -394,95 +645,57 @@ atoll (const char *p) return tmp_wide; } #endif - -/* Given a constant definition, return a hash code for its name. */ -static hashval_t -def_hash (const void *def) -{ - unsigned result, i; - const char *string = ((const struct md_constant *) def)->name; - - for (result = i = 0;*string++ != '\0'; i++) - result += ((unsigned char) *string << (i % CHAR_BIT)); - return result; -} - -/* Given two constant definitions, return true if they have the same name. */ -static int -def_name_eq_p (const void *def1, const void *def2) -{ - return ! strcmp (((const struct md_constant *) def1)->name, - ((const struct md_constant *) def2)->name); -} - -/* INFILE is a FILE pointer to read text from. TMP_CHAR is a buffer suitable - to read a name or number into. Process a define_constants directive, - starting with the optional space after the "define_constants". */ + +/* 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_constants (FILE *infile, char *tmp_char) +read_conditions (void) { int c; - htab_t defs; - c = read_skip_spaces (infile); + c = read_skip_spaces (); if (c != '[') - fatal_expected_char (infile, '[', c); - defs = md_constants; - if (! defs) - defs = htab_create (32, def_hash, def_name_eq_p, (htab_del) 0); - /* Disable constant expansion during definition processing. */ - md_constants = 0; - while ( (c = read_skip_spaces (infile)) != ']') + fatal_expected_char ('[', c); + + while ( (c = read_skip_spaces ()) != ']') { - struct md_constant *def; - void **entry_ptr; + struct md_name name; + char *expr; + int value; if (c != '(') - fatal_expected_char (infile, '(', c); - def = xmalloc (sizeof (struct md_constant)); - def->name = tmp_char; - read_name (tmp_char, infile); - entry_ptr = htab_find_slot (defs, def, TRUE); - if (! *entry_ptr) - def->name = xstrdup (tmp_char); - c = read_skip_spaces (infile); - ungetc (c, infile); - read_name (tmp_char, infile); - if (! *entry_ptr) - { - def->value = xstrdup (tmp_char); - *entry_ptr = def; - } - else - { - def = *entry_ptr; - if (strcmp (def->value, tmp_char)) - fatal_with_file_and_line (infile, - "redefinition of %s, was %s, now %s", - def->name, def->value, tmp_char); - } - c = read_skip_spaces (infile); + 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 (infile, ')', c); - } - md_constants = defs; - c = read_skip_spaces (infile); - if (c != ')') - fatal_expected_char (infile, ')', c); -} + fatal_expected_char (')', c); -/* For every constant definition, call CALLBACK with two arguments: - a pointer a pointer to the constant definition and INFO. - Stops when CALLBACK returns zero. */ -void -traverse_md_constants (htab_trav callback, void *info) -{ - if (md_constants) - htab_traverse (md_constants, callback, info); + add_c_test (expr, value); + } } static void -validate_const_int (FILE *infile, const char *string) +validate_const_int (const char *string) { const char *cp; int valid = 1; @@ -498,104 +711,218 @@ validate_const_int (FILE *infile, const char *string) if (! ISDIGIT (*cp)) valid = 0; if (!valid) - fatal_with_file_and_line (infile, "invalid decimal constant \"%s\"\n", string); + fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string); } -/* Read an rtx in printed representation from INFILE - and return an actual rtx in core constructed accordingly. - read_rtx is not used in the compiler proper, but rather in - the utilities gen*.c that construct C code from machine descriptions. */ +/* Search GROUP for a mode or code called NAME and return its numerical + identifier. */ -rtx -read_rtx (FILE *infile) +static int +find_iterator (struct iterator_group *group, const char *name) { - int i, j; - RTX_CODE tmp_code; - const char *format_ptr; - /* tmp_char is a buffer used for reading decimal integers - and names of rtx types and machine modes. - Therefore, 256 must be enough. */ - char tmp_char[256]; - rtx return_rtx; - int c; - int tmp_int; - HOST_WIDE_INT tmp_wide; + struct mapping *m; - /* Obstack used for allocating RTL objects. */ - static struct obstack rtl_obstack; - static int initialized; + m = (struct mapping *) htab_find (group->iterators, &name); + if (m != 0) + return m->index + group->num_builtins; + return group->find_builtin (name); +} - /* Linked list structure for making RTXs: */ - struct rtx_list - { - struct rtx_list *next; - rtx value; /* Value of this node. */ - }; +/* Finish reading a declaration of the form: - if (!initialized) { - obstack_init (&rtl_obstack); - initialized = 1; - } + (define... [ ... ]) -again: - c = read_skip_spaces (infile); /* Should be open paren. */ - if (c != '(') - fatal_expected_char (infile, '(', c); + from the MD file, where each is either a bare symbol name or a + "( )" pair. The "(define..." part has already been read. - read_name (tmp_char, infile); + 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; - tmp_code = UNKNOWN; + /* Read the mapping name and create a structure for it. */ + read_name (&name); + m = add_mapping (group, table, name.string); - if (! strcmp (tmp_char, "define_constants")) + c = read_skip_spaces (); + if (c != '[') + fatal_expected_char ('[', c); + + /* Read each value. */ + end_ptr = &m->values; + c = read_skip_spaces (); + do { - read_constants (infile, tmp_char); - goto again; + 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 (); } - for (i = 0; i < NUM_RTX_CODE; i++) - if (! strcmp (tmp_char, GET_RTX_NAME (i))) - { - tmp_code = (RTX_CODE) i; /* get value for name */ - break; - } + 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; +} - if (tmp_code == UNKNOWN) - fatal_with_file_and_line (infile, "unknown rtx code `%s'", tmp_char); +/* 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; - /* (NIL) stands for an expression that isn't there. */ - if (tmp_code == NIL) + /* Do one-time initialization. */ + if (queue_head == 0) { - /* Discard the closeparen. */ - while ((c = getc (infile)) && c != ')') - ; + initialize_iterators (); + queue_head = rtx_alloc (EXPR_LIST); + } - return 0; + /* 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 (tmp_code); - format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx)); + 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 (infile); + i = read_skip_spaces (); if (i == ':') { - read_name (tmp_char, infile); - for (j = 0; j < NUM_MACHINE_MODES; j++) - if (! strcmp (GET_MODE_NAME (j), tmp_char)) - break; + unsigned int mode; - if (j == MAX_MACHINE_MODE) - fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char); - - PUT_MODE (return_rtx, (enum machine_mode) j); + 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 - ungetc (i, infile); + unread_char (i); - for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++) - switch (*format_ptr++) + 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. */ @@ -604,14 +931,14 @@ again: case 'e': case 'u': - XEXP (return_rtx, i) = read_rtx (infile); + 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 (infile); - ungetc (c, infile); + c = read_skip_spaces (); + unread_char (c); if (c == ')') { XVEC (return_rtx, i) = 0; @@ -626,17 +953,19 @@ again: int list_counter = 0; rtvec return_vec = NULL_RTVEC; - c = read_skip_spaces (infile); + c = read_skip_spaces (); if (c != '[') - fatal_expected_char (infile, '[', c); + fatal_expected_char ('[', c); /* Add expressions to a list, while keeping a count. */ obstack_init (&vector_stack); - while ((c = read_skip_spaces (infile)) && c != ']') + while ((c = read_skip_spaces ()) && c != ']') { - ungetc (c, infile); + if (c == EOF) + fatal_expected_char (']', c); + unread_char (c); list_counter++; - obstack_ptr_grow (&vector_stack, read_rtx (infile)); + obstack_ptr_grow (&vector_stack, read_nested_rtx (mode_maps)); } if (list_counter > 0) { @@ -644,6 +973,8 @@ again: 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 */ @@ -651,28 +982,30 @@ again: break; case 'S': - /* 'S' is an optional string: if a closeparen follows, - just store NULL for this element. */ - c = read_skip_spaces (infile); - ungetc (c, infile); - if (c == ')') - { - XSTR (return_rtx, i) = 0; - break; - } - 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. */ - int star_if_braced = (format_ptr[-1] == 'T'); + star_if_braced = (format_ptr[i] == 'T'); - stringbuf = read_string (&rtl_obstack, infile, star_if_braced); + 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 @@ -684,16 +1017,16 @@ again: || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT)) { char line_name[20]; - const char *fn = (read_rtx_filename ? read_rtx_filename : "rtx"); + 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 (&rtl_obstack, '*'); - obstack_grow (&rtl_obstack, fn, strlen (fn)); - sprintf (line_name, ":%d", read_rtx_lineno); - obstack_grow (&rtl_obstack, line_name, strlen (line_name)+1); - stringbuf = (char *) obstack_finish (&rtl_obstack); + 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) @@ -704,20 +1037,20 @@ again: break; case 'w': - read_name (tmp_char, infile); - validate_const_int (infile, tmp_char); + read_name (&name); + validate_const_int (name.string); #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT - tmp_wide = atoi (tmp_char); + tmp_wide = atoi (name.string); #else #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG - tmp_wide = atol (tmp_char); + 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 (tmp_char); + tmp_wide = atoll (name.string); #else - tmp_wide = atoq (tmp_char); + tmp_wide = atoq (name.string); #endif #endif #endif @@ -726,23 +1059,82 @@ again: case 'i': case 'n': - read_name (tmp_char, infile); - validate_const_int (infile, tmp_char); - tmp_int = atoi (tmp_char); + read_name (&name); + validate_const_int (name.string); + tmp_int = atoi (name.string); XINT (return_rtx, i) = tmp_int; break; default: - fprintf (stderr, - "switch format wrong in rtl.read_rtx(). format was: %c.\n", - format_ptr[-1]); - fprintf (stderr, "\tfile position: %ld\n", ftell (infile)); - abort (); + gcc_unreachable (); } - c = read_skip_spaces (infile); + 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 (infile, ')', 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; +}