X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fread-rtl.c;h=e2ea54a6ed2d33ade5682507cb37972213ecea39;hb=0766e8763c0c87e7190f60f6e754b76614ccc326;hp=7e0da18f0f85cbb8aea2fd6ed8fc57fcdbec80a9;hpb=aa4c562dab1f468c0143e43f1898e6a597d994d3;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c index 7e0da18f0f8..e2ea54a6ed2 100644 --- a/gcc/read-rtl.c +++ b/gcc/read-rtl.c @@ -1,46 +1,159 @@ -/* RTL reader for GNU C Compiler. - Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001 +/* RTL reader for GCC. + Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005 Free Software Foundation, Inc. -This file is part of GNU CC. +This file is part of GCC. -GNU CC 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 version. +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 +version. -GNU CC 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. +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 GNU CC; 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 COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "bconfig.h" + +/* Disable rtl checking; it conflicts with the macro handling. */ +#undef ENABLE_RTL_CHECKING -#include "hconfig.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" #include "obstack.h" #include "hashtab.h" -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - static htab_t md_constants; -static void fatal_with_file_and_line PARAMS ((FILE *, const char *, ...)) +/* One element in a singly-linked list of (integer, string) pairs. */ +struct map_value { + struct map_value *next; + int number; + const char *string; +}; + +/* Maps a macro 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 macro or attribute. */ + const char *name; + + /* The group (modes or codes) to which the macro or attribute belongs. */ + struct macro_group *group; + + /* Gives a unique number to the attribute or macro. 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 macros. */ +struct macro_group { + /* Tables of "mapping" structures, one for attributes and one for macros. */ + htab_t attrs, macros; + + /* The number of "real" modes or codes (and by extension, the first + number available for use as a macro placeholder). */ + int num_builtins; + + /* Treat the given string as the name of a standard mode or code and + return its integer value. Use the given file for error reporting. */ + int (*find_builtin) (const char *, FILE *); + + /* Return true if the given rtx uses the given mode or code. */ + bool (*uses_macro_p) (rtx, int); + + /* Make the given rtx use the given mode or code. */ + void (*apply_macro) (rtx, int); +}; + +/* Associates PTR (which can be a string, etc.) with the file location + specified by FILENAME and LINENO. */ +struct ptr_loc { + const void *ptr; + const char *filename; + int lineno; +}; + +/* If CODE is the number of a code macro, 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 void fatal_with_file_and_line (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2 ATTRIBUTE_NORETURN; -static void fatal_expected_char PARAMS ((FILE *, int, int)) ATTRIBUTE_NORETURN; -static void read_name PARAMS ((char *, FILE *)); -static char *read_string PARAMS ((struct obstack *, FILE *, int)); -static char *read_quoted_string PARAMS ((struct obstack *, FILE *)); -static char *read_braced_string PARAMS ((struct obstack *, FILE *)); -static void read_escape PARAMS ((struct obstack *, FILE *)); -static unsigned def_hash PARAMS ((const void *)); -static int def_name_eq_p PARAMS ((const void *, const void *)); -static void read_constants PARAMS ((FILE *infile, char *tmp_char)); +static void fatal_expected_char (FILE *, int, int) ATTRIBUTE_NORETURN; +static int find_mode (const char *, FILE *); +static bool uses_mode_macro_p (rtx, int); +static void apply_mode_macro (rtx, int); +static int find_code (const char *, FILE *); +static bool uses_code_macro_p (rtx, int); +static void apply_code_macro (rtx, int); +static const char *apply_macro_to_string (const char *, struct mapping *, int); +static rtx apply_macro_to_rtx (rtx, struct mapping *, int); +static bool uses_macro_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_macro_traverse (void **, void *); +static struct mapping *add_mapping (struct macro_group *, htab_t t, + const char *, FILE *); +static struct map_value **add_map_value (struct map_value **, + int, const char *); +static void initialize_macros (void); +static void read_name (char *, FILE *); +static hashval_t leading_ptr_hash (const void *); +static int leading_ptr_eq_p (const void *, const void *); +static void set_rtx_ptr_loc (const void *, const char *, int); +static const struct ptr_loc *get_rtx_ptr_loc (const void *); +static char *read_string (FILE *, int); +static char *read_quoted_string (FILE *); +static char *read_braced_string (FILE *); +static void read_escape (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_macro (struct macro_group *, const char *, FILE *); +static struct mapping *read_mapping (struct macro_group *, htab_t, FILE *); +static void check_code_macro (struct mapping *, FILE *); +static rtx read_rtx_1 (FILE *); + +/* The mode and code macro structures. */ +static struct macro_group modes, codes; + +/* Index I is the value of BELLWETHER_CODE (I + NUM_RTX_CODE). */ +static enum rtx_code *bellwether_codes; + +/* Obstack used for allocating RTL strings. */ +static struct obstack string_obstack; + +/* A table of ptr_locs, hashed on the PTR field. */ +static htab_t ptr_locs; + +/* An obstack for the above. Plain xmalloc is a bit heavyweight for a + small structure like ptr_loc. */ +static struct obstack ptr_loc_obstack; + +/* A hash table of triples (A, B, C), where each of A, B and C is a condition + and A is equivalent to "B && C". This is used to keep track of the source + of conditions that are made up of separate rtx strings (such as the split + condition of a define_insn_and_split). */ +static htab_t joined_conditions; + +/* An obstack for allocating joined_conditions entries. */ +static struct obstack joined_conditions_obstack; /* Subroutines of read_rtx. */ @@ -51,30 +164,21 @@ int read_rtx_lineno = 1; const char *read_rtx_filename = ""; static void -fatal_with_file_and_line VPARAMS ((FILE *infile, const char *msg, ...)) +fatal_with_file_and_line (FILE *infile, const char *msg, ...) { -#ifndef ANSI_PROTOTYPES - FILE *infile; - const char *msg; -#endif - va_list ap; char context[64]; size_t i; int c; + va_list ap; - VA_START (ap, msg); - -#ifndef ANSI_PROTOTYPES - infile = va_arg (ap, FILE *); - msg = va_arg (ap, const char *); -#endif + va_start (ap, msg); fprintf (stderr, "%s:%d: ", read_rtx_filename, read_rtx_lineno); vfprintf (stderr, msg, ap); putc ('\n', stderr); /* Gather some following context. */ - for (i = 0; i < sizeof(context)-1; ++i) + for (i = 0; i < sizeof (context)-1; ++i) { c = getc (infile); if (c == EOF) @@ -96,24 +200,517 @@ fatal_with_file_and_line VPARAMS ((FILE *infile, const char *msg, ...)) invalid data. */ static void -fatal_expected_char (infile, expected_c, actual_c) - FILE *infile; - int expected_c, actual_c; +fatal_expected_char (FILE *infile, int expected_c, int actual_c) { fatal_with_file_and_line (infile, "expected character `%c', found `%c'", expected_c, actual_c); } +/* Implementations of the macro_group callbacks for modes. */ + +static int +find_mode (const char *name, FILE *infile) +{ + 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 (infile, "unknown mode `%s'", name); +} + +static bool +uses_mode_macro_p (rtx x, int mode) +{ + return (int) GET_MODE (x) == mode; +} + +static void +apply_mode_macro (rtx x, int mode) +{ + PUT_MODE (x, mode); +} + +/* Implementations of the macro_group callbacks for codes. */ + +static int +find_code (const char *name, FILE *infile) +{ + 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 (infile, "unknown rtx code `%s'", name); +} + +static bool +uses_code_macro_p (rtx x, int code) +{ + return (int) GET_CODE (x) == code; +} + +static void +apply_code_macro (rtx x, int code) +{ + PUT_CODE (x, code); +} + +/* Given that MACRO 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_macro_to_string (const char *string, struct mapping *macro, int value) +{ + char *base, *copy, *p, *attr, *start, *end; + struct mapping *m; + struct map_value *v; + + if (string == 0) + return string; + + base = p = copy = ASTRDUP (string); + while ((start = strchr (p, '<')) && (end = strchr (start, '>'))) + { + p = start + 1; + + /* If there's a "macro:" prefix, check whether the macro name matches. + Set ATTR to the start of the attribute name. */ + attr = strchr (p, ':'); + if (attr == 0 || attr > end) + attr = p; + else + { + if (strncmp (p, macro->name, attr - p) != 0 + || macro->name[attr - p] != 0) + continue; + attr++; + } + + /* Find the attribute specification. */ + *end = 0; + m = (struct mapping *) htab_find (macro->group->attrs, &attr); + *end = '>'; + if (m == 0) + continue; + + /* Find the attribute value for VALUE. */ + for (v = m->values; v != 0; v = v->next) + if (v->number == value) + break; + 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 = obstack_finish (&string_obstack); + copy_rtx_ptr_loc (copy, string); + return copy; + } + return string; +} + +/* Return a copy of ORIGINAL in which all uses of MACRO have been + replaced by VALUE. */ + +static rtx +apply_macro_to_rtx (rtx original, struct mapping *macro, int value) +{ + struct macro_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_SIZE (bellwether_code)); + + /* Change the mode or code itself. */ + group = macro->group; + if (group->uses_macro_p (x, macro->index + group->num_builtins)) + group->apply_macro (x, value); + + /* 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_macro_to_string (XTMPL (x, i), macro, value); + break; + + case 'S': + case 's': + XSTR (x, i) = apply_macro_to_string (XSTR (x, i), macro, value); + break; + + case 'e': + XEXP (x, i) = apply_macro_to_rtx (XEXP (x, i), macro, value); + 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_macro_to_rtx (XVECEXP (original, i, j), + macro, value); + } + break; + + default: + break; + } + return x; +} + +/* Return true if X (or some subexpression of X) uses macro MACRO. */ + +static bool +uses_macro_p (rtx x, struct mapping *macro) +{ + struct macro_group *group; + const char *format_ptr; + int i, j; + + if (x == 0) + return false; + + group = macro->group; + if (group->uses_macro_p (x, macro->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_macro_p (XEXP (x, i), macro)) + return true; + break; + + case 'V': + case 'E': + if (XVEC (x, i)) + for (j = 0; j < XVECLEN (x, i); j++) + if (uses_macro_p (XVECEXP (x, i, j), macro)) + 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 macro in *SLOT. Replace each such rtx + with a list of expansions. */ + +static int +apply_macro_traverse (void **slot, void *data) +{ + struct mapping *macro; + struct map_value *v; + rtx elem, new_elem, original, x; + + macro = (struct mapping *) *slot; + for (elem = (rtx) data; elem != 0; elem = XEXP (elem, 1)) + if (uses_macro_p (XEXP (elem, 0), macro)) + { + original = XEXP (elem, 0); + for (v = macro->values; v != 0; v = v->next) + { + x = apply_macro_to_rtx (original, macro, v->number); + add_condition_to_rtx (x, v->string); + if (v != macro->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, GROUP is the group to which it belongs, and INFILE + is the file that defined the mapping. */ + +static struct mapping * +add_mapping (struct macro_group *group, htab_t table, + const char *name, FILE *infile) +{ + 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 (infile, "`%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_macros (void) +{ + struct mapping *lower, *upper; + struct map_value **lower_ptr, **upper_ptr; + char *copy, *p; + int i; + + modes.attrs = htab_create (13, def_hash, def_name_eq_p, 0); + modes.macros = htab_create (13, def_hash, def_name_eq_p, 0); + modes.num_builtins = MAX_MACHINE_MODE; + modes.find_builtin = find_mode; + modes.uses_macro_p = uses_mode_macro_p; + modes.apply_macro = apply_mode_macro; + + codes.attrs = htab_create (13, def_hash, def_name_eq_p, 0); + codes.macros = htab_create (13, def_hash, def_name_eq_p, 0); + codes.num_builtins = NUM_RTX_CODE; + codes.find_builtin = find_code; + codes.uses_macro_p = uses_code_macro_p; + codes.apply_macro = apply_code_macro; + + lower = add_mapping (&modes, modes.attrs, "mode", 0); + upper = add_mapping (&modes, modes.attrs, "MODE", 0); + 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", 0); + upper = add_mapping (&codes, codes.attrs, "CODE", 0); + 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); + } +} + +/* Return a hash value for the pointer pointed to by DEF. */ + +static hashval_t +leading_ptr_hash (const void *def) +{ + return htab_hash_pointer (*(const void *const *) def); +} + +/* Return true if DEF1 and DEF2 are pointers to the same pointer. */ + +static int +leading_ptr_eq_p (const void *def1, const void *def2) +{ + return *(const void *const *) def1 == *(const void *const *) def2; +} + +/* Associate PTR with the file position given by FILENAME and LINENO. */ + +static void +set_rtx_ptr_loc (const void *ptr, const char *filename, int lineno) +{ + struct ptr_loc *loc; + + loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack, + sizeof (struct ptr_loc)); + loc->ptr = ptr; + loc->filename = filename; + loc->lineno = lineno; + *htab_find_slot (ptr_locs, loc, INSERT) = loc; +} + +/* Return the position associated with pointer PTR. Return null if no + position was set. */ + +static const struct ptr_loc * +get_rtx_ptr_loc (const void *ptr) +{ + return (const struct ptr_loc *) htab_find (ptr_locs, &ptr); +} + +/* Associate NEW_PTR with the same file position as OLD_PTR. */ + +void +copy_rtx_ptr_loc (const void *new_ptr, const void *old_ptr) +{ + const struct ptr_loc *loc = get_rtx_ptr_loc (old_ptr); + if (loc != 0) + set_rtx_ptr_loc (new_ptr, loc->filename, loc->lineno); +} + +/* If PTR is associated with a known file position, print a #line + directive for it. */ + +void +print_rtx_ptr_loc (const void *ptr) +{ + const struct ptr_loc *loc = get_rtx_ptr_loc (ptr); + if (loc != 0) + printf ("#line %d \"%s\"\n", loc->lineno, loc->filename); +} + +/* Return a condition that satisfies both COND1 and COND2. Either string + may be null or empty. */ + +const char * +join_c_conditions (const char *cond1, const char *cond2) +{ + char *result; + const void **entry; + + if (cond1 == 0 || cond1[0] == 0) + return cond2; + + if (cond2 == 0 || cond2[0] == 0) + return cond1; + + result = concat ("(", cond1, ") && (", cond2, ")", NULL); + obstack_ptr_grow (&joined_conditions_obstack, result); + obstack_ptr_grow (&joined_conditions_obstack, cond1); + obstack_ptr_grow (&joined_conditions_obstack, cond2); + entry = obstack_finish (&joined_conditions_obstack); + *htab_find_slot (joined_conditions, entry, INSERT) = entry; + return result; +} + +/* Print condition COND, wrapped in brackets. If COND was created by + join_c_conditions, recursively invoke this function for the original + conditions and join the result with "&&". Otherwise print a #line + directive for COND if its original file position is known. */ + +void +print_c_condition (const char *cond) +{ + const void **halves = htab_find (joined_conditions, &cond); + if (halves != 0) + { + printf ("("); + print_c_condition (halves[1]); + printf (" && "); + print_c_condition (halves[2]); + printf (")"); + } + else + { + putc ('\n', stdout); + print_rtx_ptr_loc (cond); + printf ("(%s)", cond); + } +} + /* 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. */ int -read_skip_spaces (infile) - FILE *infile; +read_skip_spaces (FILE *infile) { - register int c; + int c; + while (1) { c = getc (infile); @@ -135,7 +732,7 @@ read_skip_spaces (infile) case '/': { - register int prevc; + int prevc; c = getc (infile); if (c != '*') fatal_expected_char (infile, '*', c); @@ -162,19 +759,17 @@ read_skip_spaces (infile) It is terminated by any of the punctuation chars of rtx printed syntax. */ static void -read_name (str, infile) - char *str; - FILE *infile; +read_name (char *str, FILE *infile) { - register char *p; - register int c; + char *p; + int c; - c = read_skip_spaces(infile); + c = read_skip_spaces (infile); p = str; while (1) { - if (c == ' ' || c == '\n' || c == '\t' || c == '\f') + if (c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r') break; if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/' || c == '(' || c == '[') @@ -203,7 +798,7 @@ read_name (str, infile) struct md_constant tmp_def; tmp_def.name = p; - def = htab_find (md_constants, &tmp_def); + def = (struct md_constant *) htab_find (md_constants, &tmp_def); if (def) p = def->value; } while (def); @@ -215,11 +810,10 @@ read_name (str, infile) /* Subroutine of the string readers. Handles backslash escapes. Caller has read the backslash, but not placed it into the obstack. */ static void -read_escape (ob, infile) - struct obstack *ob; - FILE *infile; +read_escape (FILE *infile) { int c = getc (infile); + switch (c) { /* Backslash-newline is replaced by nothing, as in C. */ @@ -245,35 +839,34 @@ read_escape (ob, infile) 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, '\\'); + obstack_1grow (&string_obstack, '\\'); break; /* \; makes stuff for a C string constant containing newline and tab. */ case ';': - obstack_grow (ob, "\\n\\t", 4); + obstack_grow (&string_obstack, "\\n\\t", 4); return; /* 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, '\\'); + obstack_1grow (&string_obstack, '\\'); break; } - obstack_1grow (ob, c); + obstack_1grow (&string_obstack, c); } - + /* Read a double-quoted string onto the obstack. Caller has scanned the leading quote. */ static char * -read_quoted_string (ob, infile) - struct obstack *ob; - FILE *infile; +read_quoted_string (FILE *infile) { int c; + while (1) { c = getc (infile); /* Read the string */ @@ -281,34 +874,34 @@ read_quoted_string (ob, infile) read_rtx_lineno++; else if (c == '\\') { - read_escape (ob, infile); + read_escape (infile); continue; } else if (c == '"') break; - obstack_1grow (ob, c); + obstack_1grow (&string_obstack, c); } - obstack_1grow (ob, 0); - return obstack_finish (ob); + obstack_1grow (&string_obstack, 0); + return (char *) obstack_finish (&string_obstack); } -/* Read a braced string (a la Tcl) onto the obstack. Caller has - scanned the leading brace. Note that unlike quoted strings, +/* Read a braced string (a la Tcl) onto the string 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 (ob, infile) - struct obstack *ob; - FILE *infile; +read_braced_string (FILE *infile) { int c; int brace_depth = 1; /* caller-processed */ + unsigned long starting_read_rtx_lineno = read_rtx_lineno; - obstack_1grow (ob, '{'); + obstack_1grow (&string_obstack, '{'); while (brace_depth) { c = getc (infile); /* Read the string */ + if (c == '\n') read_rtx_lineno++; else if (c == '{') @@ -317,15 +910,19 @@ read_braced_string (ob, infile) brace_depth--; else if (c == '\\') { - read_escape (ob, infile); + read_escape (infile); continue; } + else if (c == EOF) + fatal_with_file_and_line + (infile, "missing closing } for opening brace on line %lu", + starting_read_rtx_lineno); - obstack_1grow (ob, c); + obstack_1grow (&string_obstack, c); } - - obstack_1grow (ob, 0); - return obstack_finish (ob); + + obstack_1grow (&string_obstack, 0); + return (char *) obstack_finish (&string_obstack); } /* Read some kind of string constant. This is the high-level routine @@ -333,14 +930,11 @@ read_braced_string (ob, infile) and dispatch to the appropriate string constant reader. */ static char * -read_string (ob, infile, star_if_braced) - struct obstack *ob; - FILE *infile; - int star_if_braced; +read_string (FILE *infile, int star_if_braced) { char *stringbuf; int saw_paren = 0; - int c; + int c, old_lineno; c = read_skip_spaces (infile); if (c == '(') @@ -349,17 +943,18 @@ read_string (ob, infile, star_if_braced) c = read_skip_spaces (infile); } + old_lineno = read_rtx_lineno; if (c == '"') - stringbuf = read_quoted_string (ob, infile); + stringbuf = read_quoted_string (infile); else if (c == '{') { if (star_if_braced) - obstack_1grow (ob, '*'); - stringbuf = read_braced_string (ob, infile); + obstack_1grow (&string_obstack, '*'); + stringbuf = read_braced_string (infile); } else fatal_with_file_and_line (infile, "expected `\"' or `{', found `%c'", c); - + if (saw_paren) { c = read_skip_spaces (infile); @@ -367,20 +962,22 @@ read_string (ob, infile, star_if_braced) fatal_expected_char (infile, ')', c); } + set_rtx_ptr_loc (stringbuf, read_rtx_filename, old_lineno); return stringbuf; } /* 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(p) - const char *p; +atoll (const char *p) { int neg = 0; HOST_WIDE_INT tmp_wide; - while (ISSPACE(*p)) + while (ISSPACE (*p)) p++; if (*p == '-') neg = 1, p++; @@ -388,13 +985,13 @@ atoll(p) p++; tmp_wide = 0; - while (ISDIGIT(*p)) + 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; + tmp_wide = (~(unsigned HOST_WIDE_INT) 0) >> 1; break; } tmp_wide = new_wide; @@ -407,35 +1004,33 @@ atoll(p) } #endif -/* Given a constant definition, return a hash code for its name. */ -static unsigned -def_hash (def) - const void *def; +/* Given an object that starts with a char * name field, 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; + const char *string = *(const char *const *) def; - for (result = i = 0;*string++ != '\0'; i++) + 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. */ +/* Given two objects that start with char * name fields, return true if + they have the same name. */ static int -def_name_eq_p (def1, def2) - const void *def1, *def2; +def_name_eq_p (const void *def1, const void *def2) { - return ! strcmp (((const struct md_constant *)def1)->name, - ((const struct md_constant *)def2)->name); + return ! strcmp (*(const char *const *) def1, + *(const char *const *) def2); } /* 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". */ static void -read_constants (infile, tmp_char) - FILE *infile; - char *tmp_char; +read_constants (FILE *infile, char *tmp_char) { int c; htab_t defs; @@ -455,10 +1050,10 @@ read_constants (infile, tmp_char) if (c != '(') fatal_expected_char (infile, '(', c); - def = xmalloc (sizeof (struct md_constant)); + def = XNEW (struct md_constant); def->name = tmp_char; read_name (tmp_char, infile); - entry_ptr = htab_find_slot (defs, def, TRUE); + entry_ptr = htab_find_slot (defs, def, INSERT); if (! *entry_ptr) def->name = xstrdup (tmp_char); c = read_skip_spaces (infile); @@ -471,7 +1066,7 @@ read_constants (infile, tmp_char) } else { - def = *entry_ptr; + def = (struct md_constant *) *entry_ptr; if (strcmp (def->value, tmp_char)) fatal_with_file_and_line (infile, "redefinition of %s, was %s, now %s", @@ -491,39 +1086,197 @@ read_constants (infile, tmp_char) a pointer a pointer to the constant definition and INFO. Stops when CALLBACK returns zero. */ void -traverse_md_constants (callback, info) - htab_trav callback; - void *info; +traverse_md_constants (htab_trav callback, void *info) { if (md_constants) htab_traverse (md_constants, callback, info); } -/* Read an rtx in printed representation from INFILE - and return an actual rtx in core constructed accordingly. +static void +validate_const_int (FILE *infile, 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 (infile, "invalid decimal constant \"%s\"\n", string); +} + +/* Search GROUP for a mode or code called NAME and return its numerical + identifier. INFILE is the file that contained NAME. */ + +static int +find_macro (struct macro_group *group, const char *name, FILE *infile) +{ + struct mapping *m; + + m = (struct mapping *) htab_find (group->macros, &name); + if (m != 0) + return m->index + group->num_builtins; + return group->find_builtin (name, infile); +} + +/* Finish reading a declaration of the form: + + (define... [ ... ]) + + from INFILE, 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 macro_group *group, htab_t table, FILE *infile) +{ + char tmp_char[256]; + 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 (tmp_char, infile); + m = add_mapping (group, table, tmp_char, infile); + + c = read_skip_spaces (infile); + if (c != '[') + fatal_expected_char (infile, '[', c); + + /* Read each value. */ + end_ptr = &m->values; + c = read_skip_spaces (infile); + do + { + if (c != '(') + { + /* A bare symbol name that is implicitly paired to an + empty string. */ + ungetc (c, infile); + read_name (tmp_char, infile); + string = ""; + } + else + { + /* A "(name string)" pair. */ + read_name (tmp_char, infile); + string = read_string (infile, false); + c = read_skip_spaces (infile); + if (c != ')') + fatal_expected_char (infile, ')', c); + } + number = group->find_builtin (tmp_char, infile); + end_ptr = add_map_value (end_ptr, number, string); + c = read_skip_spaces (infile); + } + while (c != ']'); + + c = read_skip_spaces (infile); + if (c != ')') + fatal_expected_char (infile, ')', c); + + return m; +} + +/* Check newly-created code macro MACRO to see whether every code has the + same format. Initialize the macro's entry in bellwether_codes. */ + +static void +check_code_macro (struct mapping *macro, FILE *infile) +{ + struct map_value *v; + enum rtx_code bellwether; + + bellwether = macro->values->number; + for (v = macro->values->next; v != 0; v = v->next) + if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0) + fatal_with_file_and_line (infile, "code macro `%s' combines " + "different rtx formats", macro->name); + + bellwether_codes = XRESIZEVEC (enum rtx_code, bellwether_codes, + macro->index + 1); + bellwether_codes[macro->index] = bellwether; +} + +/* Read an rtx in printed representation from INFILE and store its + core representation in *X. Also store the line number of the + opening '(' in *LINENO. Return true on success or false if the + end of file has been reached. + read_rtx is not used in the compiler proper, but rather in the utilities gen*.c that construct C code from machine descriptions. */ -rtx -read_rtx (infile) - FILE *infile; +bool +read_rtx (FILE *infile, rtx *x, int *lineno) { - register int i, j; - RTX_CODE tmp_code; - register const char *format_ptr; + static rtx queue_head, queue_next; + static int queue_lineno; + int c; + + /* Do one-time initialization. */ + if (queue_head == 0) + { + initialize_macros (); + obstack_init (&string_obstack); + queue_head = rtx_alloc (EXPR_LIST); + ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0); + obstack_init (&ptr_loc_obstack); + joined_conditions = htab_create (161, leading_ptr_hash, + leading_ptr_eq_p, 0); + obstack_init (&joined_conditions_obstack); + } + + if (queue_next == 0) + { + c = read_skip_spaces (infile); + if (c == EOF) + return false; + ungetc (c, infile); + + queue_next = queue_head; + queue_lineno = read_rtx_lineno; + XEXP (queue_next, 0) = read_rtx_1 (infile); + XEXP (queue_next, 1) = 0; + + htab_traverse (modes.macros, apply_macro_traverse, queue_next); + htab_traverse (codes.macros, apply_macro_traverse, queue_next); + } + + *x = XEXP (queue_next, 0); + *lineno = queue_lineno; + queue_next = XEXP (queue_next, 1); + + return true; +} + +/* Subroutine of read_rtx that reads one construct from INFILE but + doesn't apply any macros. */ + +static rtx +read_rtx_1 (FILE *infile) +{ + int i; + RTX_CODE real_code, bellwether_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; - register int c; + int c; int tmp_int; HOST_WIDE_INT tmp_wide; - /* Obstack used for allocating RTL objects. */ - static struct obstack rtl_obstack; - static int initialized; - /* Linked list structure for making RTXs: */ struct rtx_list { @@ -531,48 +1284,52 @@ read_rtx (infile) rtx value; /* Value of this node. */ }; - if (!initialized) { - obstack_init (&rtl_obstack); - initialized = 1; - } - -again: + again: c = read_skip_spaces (infile); /* Should be open paren. */ if (c != '(') fatal_expected_char (infile, '(', c); read_name (tmp_char, infile); - - tmp_code = UNKNOWN; - - if (! strcmp (tmp_char, "define_constants")) + if (strcmp (tmp_char, "nil") == 0) + { + /* (nil) stands for an expression that isn't there. */ + c = read_skip_spaces (infile); + if (c != ')') + fatal_expected_char (infile, ')', c); + return 0; + } + if (strcmp (tmp_char, "define_constants") == 0) { read_constants (infile, tmp_char); goto again; } - 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; - } - - if (tmp_code == UNKNOWN) - fatal_with_file_and_line (infile, "unknown rtx code `%s'", tmp_char); - - /* (NIL) stands for an expression that isn't there. */ - if (tmp_code == NIL) + if (strcmp (tmp_char, "define_mode_attr") == 0) { - /* Discard the closeparen. */ - while ((c = getc (infile)) && c != ')') - ; - - return 0; + read_mapping (&modes, modes.attrs, infile); + goto again; + } + if (strcmp (tmp_char, "define_mode_macro") == 0) + { + read_mapping (&modes, modes.macros, infile); + goto again; + } + if (strcmp (tmp_char, "define_code_attr") == 0) + { + read_mapping (&codes, codes.attrs, infile); + goto again; + } + if (strcmp (tmp_char, "define_code_macro") == 0) + { + check_code_macro (read_mapping (&codes, codes.macros, infile), infile); + goto again; } + real_code = find_macro (&codes, tmp_char, infile); + 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. */ @@ -581,20 +1338,13 @@ again: if (i == ':') { read_name (tmp_char, infile); - for (j = 0; j < NUM_MACHINE_MODES; j++) - if (! strcmp (GET_MODE_NAME (j), tmp_char)) - break; - - if (j == MAX_MACHINE_MODE) - fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char); - - PUT_MODE (return_rtx, (enum machine_mode) j); + PUT_MODE (return_rtx, find_macro (&modes, tmp_char, infile)); } else ungetc (i, infile); - 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. */ @@ -603,7 +1353,7 @@ again: case 'e': case 'u': - XEXP (return_rtx, i) = read_rtx (infile); + XEXP (return_rtx, i) = read_rtx_1 (infile); break; case 'V': @@ -615,7 +1365,7 @@ again: { XVEC (return_rtx, i) = 0; break; - } + } /* Now process the vector. */ case 'E': @@ -629,13 +1379,13 @@ again: if (c != '[') fatal_expected_char (infile, '[', c); - /* add expressions to a list, while keeping a count */ + /* Add expressions to a list, while keeping a count. */ obstack_init (&vector_stack); while ((c = read_skip_spaces (infile)) && c != ']') { ungetc (c, infile); list_counter++; - obstack_ptr_grow (&vector_stack, (PTR) read_rtx (infile)); + obstack_ptr_grow (&vector_stack, read_rtx_1 (infile)); } if (list_counter > 0) { @@ -643,6 +1393,9 @@ 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 (infile, + "vector must have at least one element"); XVEC (return_rtx, i) = return_vec; obstack_free (&vector_stack, NULL); /* close bracket gotten */ @@ -650,28 +1403,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 (infile); + ungetc (c, infile); + 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'); - - stringbuf = read_string (&rtl_obstack, infile, star_if_braced); + star_if_braced = (format_ptr[i] == 'T'); + + stringbuf = read_string (infile, 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 @@ -688,11 +1443,11 @@ again: for (slash = fn; *slash; slash ++) if (*slash == '/' || *slash == '\\' || *slash == ':') fn = slash + 1; - obstack_1grow (&rtl_obstack, '*'); - obstack_grow (&rtl_obstack, fn, strlen (fn)); + obstack_1grow (&string_obstack, '*'); + obstack_grow (&string_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_grow (&string_obstack, line_name, strlen (line_name)+1); + stringbuf = (char *) obstack_finish (&string_obstack); } if (star_if_braced) @@ -704,6 +1459,7 @@ again: case 'w': read_name (tmp_char, infile); + validate_const_int (infile, tmp_char); #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT tmp_wide = atoi (tmp_char); #else @@ -725,6 +1481,7 @@ again: case 'i': case 'n': read_name (tmp_char, infile); + validate_const_int (infile, tmp_char); tmp_int = atoi (tmp_char); XINT (return_rtx, i) = tmp_int; break; @@ -732,7 +1489,7 @@ again: default: fprintf (stderr, "switch format wrong in rtl.read_rtx(). format was: %c.\n", - format_ptr[-1]); + format_ptr[i]); fprintf (stderr, "\tfile position: %ld\n", ftell (infile)); abort (); }