diff options
Diffstat (limited to 'contrib/gcc/gensupport.c')
-rw-r--r-- | contrib/gcc/gensupport.c | 409 |
1 files changed, 233 insertions, 176 deletions
diff --git a/contrib/gcc/gensupport.c b/contrib/gcc/gensupport.c index 415df01..53172dd 100644 --- a/contrib/gcc/gensupport.c +++ b/contrib/gcc/gensupport.c @@ -1,5 +1,5 @@ /* Support routines for the various generation passes. - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -23,18 +23,18 @@ #include "rtl.h" #include "obstack.h" #include "errors.h" +#include "hashtab.h" #include "gensupport.h" /* In case some macros used by files we include need it, define this here. */ int target_flags; +int insn_elision = 1; + static struct obstack obstack; struct obstack *rtl_obstack = &obstack; -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - static int sequence_num; static int errors; @@ -42,6 +42,8 @@ static int predicable_default; static const char *predicable_true; static const char *predicable_false; +static htab_t condition_table; + static char *base_dir = NULL; /* We initially queue all patterns, process the define_insn and @@ -50,6 +52,7 @@ static char *base_dir = NULL; struct queue_elem { rtx data; + const char *filename; int lineno; struct queue_elem *next; }; @@ -63,7 +66,8 @@ static struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue; static struct queue_elem *other_queue; static struct queue_elem **other_tail = &other_queue; -static void queue_pattern PARAMS ((rtx, struct queue_elem ***, int)); +static void queue_pattern PARAMS ((rtx, struct queue_elem ***, + const char *, int)); /* Current maximum length of directory names in the search path for include files. (Altered as we get more of them.) */ @@ -76,10 +80,10 @@ struct file_name_list const char *fname; }; -struct file_name_list *include = 0; /* First dir to search */ +struct file_name_list *first_dir_md_include = 0; /* First dir to search */ /* First dir to search for <file> */ struct file_name_list *first_bracket_include = 0; -struct file_name_list *last_include = 0; /* Last in chain */ +struct file_name_list *last_dir_md_include = 0; /* Last in chain */ static void remove_constraints PARAMS ((rtx)); static void process_rtx PARAMS ((rtx, int)); @@ -97,9 +101,8 @@ static const char *alter_output_for_insn PARAMS ((struct queue_elem *, int, int)); static void process_one_cond_exec PARAMS ((struct queue_elem *)); static void process_define_cond_exec PARAMS ((void)); -static int process_include PARAMS ((rtx, int)); +static void process_include PARAMS ((rtx, int)); static char *save_string PARAMS ((const char *, int)); -static int init_include_reader PARAMS ((FILE *)); void message_with_line VPARAMS ((int lineno, const char *msg, ...)) @@ -132,13 +135,15 @@ gen_rtx_CONST_INT (mode, arg) /* Queue PATTERN on LIST_TAIL. */ static void -queue_pattern (pattern, list_tail, lineno) +queue_pattern (pattern, list_tail, filename, lineno) rtx pattern; struct queue_elem ***list_tail; + const char *filename; int lineno; { struct queue_elem *e = (struct queue_elem *) xmalloc (sizeof (*e)); e->data = pattern; + e->filename = filename; e->lineno = lineno; e->next = NULL; **list_tail = e; @@ -179,142 +184,83 @@ remove_constraints (part) } } -/* The entry point for initializing the reader. */ - -static int -init_include_reader (inf) - FILE *inf; -{ - int c; - - errors = 0; - - /* Read the entire file. */ - while (1) - { - rtx desc; - int lineno; - - c = read_skip_spaces (inf); - if (c == EOF) - break; - - ungetc (c, inf); - lineno = read_rtx_lineno; - desc = read_rtx (inf); - process_rtx (desc, lineno); - } - fclose (inf); - - /* Process define_cond_exec patterns. */ - if (define_cond_exec_queue != NULL) - process_define_cond_exec (); - - return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; -} - /* Process an include file assuming that it lives in gcc/config/{target}/ - if the include looks line (include "file" ) */ -static int + if the include looks like (include "file"). */ + +static void process_include (desc, lineno) rtx desc; int lineno; { const char *filename = XSTR (desc, 0); - char *pathname = NULL; + const char *old_filename; + int old_lineno; + char *pathname; FILE *input_file; - char *fname = NULL; - struct file_name_list *stackp; - int flen; - stackp = include; - - /* If specified file name is absolute, just open it. */ - if (IS_ABSOLUTE_PATHNAME (filename) || !stackp) + /* If specified file name is absolute, skip the include stack. */ + if (! IS_ABSOLUTE_PATHNAME (filename)) { - if (base_dir) - { - pathname = xmalloc (strlen (base_dir) + strlen (filename) + 1); - pathname = strcpy (pathname, base_dir); - strcat (pathname, filename); - strcat (pathname, "\0"); - } - else - { - pathname = xstrdup (filename); - } - read_rtx_filename = pathname; - input_file = fopen (pathname, "r"); + struct file_name_list *stackp; - if (input_file == 0) + /* Search directory path, trying to open the file. */ + for (stackp = first_dir_md_include; stackp; stackp = stackp->next) { - perror (pathname); - return FATAL_EXIT_CODE; + static const char sep[2] = { DIR_SEPARATOR, '\0' }; + + pathname = concat (stackp->fname, sep, filename, NULL); + input_file = fopen (pathname, "r"); + if (input_file != NULL) + goto success; + free (pathname); } } - else if (stackp) - { - - flen = strlen (filename); - - fname = (char *) xmalloc (max_include_len + flen + 2); - /* + 2 above for slash and terminating null. */ + if (base_dir) + pathname = concat (base_dir, filename, NULL); + else + pathname = xstrdup (filename); + input_file = fopen (pathname, "r"); + if (input_file == NULL) + { + free (pathname); + message_with_line (lineno, "include file `%s' not found", filename); + errors = 1; + return; + } + success: - /* Search directory path, trying to open the file. - Copy each filename tried into FNAME. */ + /* Save old cursor; setup new for the new file. Note that "lineno" the + argument to this function is the beginning of the include statement, + while read_rtx_lineno has already been advanced. */ + old_filename = read_rtx_filename; + old_lineno = read_rtx_lineno; + read_rtx_filename = pathname; + read_rtx_lineno = 1; - for (; stackp; stackp = stackp->next) - { - if (stackp->fname) - { - strcpy (fname, stackp->fname); - strcat (fname, "/"); - fname[strlen (fname) + flen] = 0; - } - else - { - fname[0] = 0; - } - strncat (fname, (const char *) filename, flen); - read_rtx_filename = fname; - input_file = fopen (fname, "r"); - if (input_file != NULL) - break; - } - if (stackp == NULL) - { - if (strchr (fname, '/') == NULL || strchr (fname, '\\' ) || base_dir) - { - if (base_dir) - { - pathname = - xmalloc (strlen (base_dir) + strlen (filename) + 1); - pathname = strcpy (pathname, base_dir); - strcat (pathname, filename); - strcat (pathname, "\0"); - } - else - pathname = xstrdup (filename); - } - read_rtx_filename = pathname; - input_file = fopen (pathname, "r"); + /* Read the entire file. */ + while (1) + { + rtx desc; + int c; - if (input_file == 0) - { - perror (filename); - return FATAL_EXIT_CODE; - } - } + c = read_skip_spaces (input_file); + if (c == EOF) + break; + ungetc (c, input_file); + lineno = read_rtx_lineno; + desc = read_rtx (input_file); + process_rtx (desc, lineno); } - if (init_include_reader (input_file) == FATAL_EXIT_CODE) - message_with_line (lineno, "read errors found in include file %s\n", pathname); + /* Do not free pathname. It is attached to the various rtx queue + elements. */ + + read_rtx_filename = old_filename; + read_rtx_lineno = old_lineno; - if (fname) - free (fname); - return SUCCESS_EXIT_CODE; + fclose (input_file); } /* Process a top level rtx in some way, queueing as appropriate. */ @@ -327,24 +273,19 @@ process_rtx (desc, lineno) switch (GET_CODE (desc)) { case DEFINE_INSN: - queue_pattern (desc, &define_insn_tail, lineno); + queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno); break; case DEFINE_COND_EXEC: - queue_pattern (desc, &define_cond_exec_tail, lineno); + queue_pattern (desc, &define_cond_exec_tail, read_rtx_filename, lineno); break; case DEFINE_ATTR: - queue_pattern (desc, &define_attr_tail, lineno); + queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno); break; case INCLUDE: - if (process_include (desc, lineno) == FATAL_EXIT_CODE) - { - const char *filename = XSTR (desc, 0); - message_with_line (lineno, "include file at %s not found\n", - filename); - } + process_include (desc, lineno); break; case DEFINE_INSN_AND_SPLIT: @@ -369,18 +310,7 @@ process_rtx (desc, lineno) insn condition to create the new split condition. */ split_cond = XSTR (desc, 4); if (split_cond[0] == '&' && split_cond[1] == '&') - { - const char *insn_cond = XSTR (desc, 2); - size_t insn_cond_len = strlen (insn_cond); - size_t split_cond_len = strlen (split_cond); - char *combined; - - combined = (char *) xmalloc (insn_cond_len + split_cond_len + 1); - memcpy (combined, insn_cond, insn_cond_len); - memcpy (combined + insn_cond_len, split_cond, split_cond_len + 1); - - split_cond = combined; - } + split_cond = concat (XSTR (desc, 2), split_cond, NULL); XSTR (split, 1) = split_cond; XVEC (split, 2) = XVEC (desc, 5); XSTR (split, 3) = XSTR (desc, 6); @@ -391,13 +321,13 @@ process_rtx (desc, lineno) XVEC (desc, 4) = attr; /* Queue them. */ - queue_pattern (desc, &define_insn_tail, lineno); - queue_pattern (split, &other_tail, lineno); + queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno); + queue_pattern (split, &other_tail, read_rtx_filename, lineno); break; } default: - queue_pattern (desc, &other_tail, lineno); + queue_pattern (desc, &other_tail, read_rtx_filename, lineno); break; } } @@ -500,7 +430,6 @@ identify_predicable_attribute () struct queue_elem *elem; char *p_true, *p_false; const char *value; - size_t len; /* Look for the DEFINE_ATTR for `predicable', which must exist. */ for (elem = define_attr_queue; elem ; elem = elem->next) @@ -514,10 +443,7 @@ identify_predicable_attribute () found: value = XSTR (elem->data, 1); - len = strlen (value); - p_false = (char *) xmalloc (len + 1); - memcpy (p_false, value, len + 1); - + p_false = xstrdup (value); p_true = strchr (p_false, ','); if (p_true == NULL || strchr (++p_true, ',') != NULL) { @@ -735,8 +661,6 @@ alter_test_for_insn (ce_elem, insn_elem) struct queue_elem *ce_elem, *insn_elem; { const char *ce_test, *insn_test; - char *new_test; - size_t len, ce_len, insn_len; ce_test = XSTR (ce_elem->data, 1); insn_test = XSTR (insn_elem->data, 2); @@ -745,14 +669,7 @@ alter_test_for_insn (ce_elem, insn_elem) if (!insn_test || *insn_test == '\0') return ce_test; - ce_len = strlen (ce_test); - insn_len = strlen (insn_test); - len = 1 + ce_len + 1 + 4 + 1 + insn_len + 1 + 1; - new_test = (char *) xmalloc (len); - - sprintf (new_test, "(%s) && (%s)", ce_test, insn_test); - - return new_test; + return concat ("(", ce_test, ") && (", insn_test, ")", NULL); } /* Adjust all of the operand numbers in OLD to match the shift they'll @@ -917,7 +834,8 @@ process_one_cond_exec (ce_elem) patterns into the define_insn chain just after their generator is something we'll have to experiment with. */ - queue_pattern (insn, &other_tail, insn_elem->lineno); + queue_pattern (insn, &other_tail, insn_elem->filename, + insn_elem->lineno); } } @@ -981,11 +899,11 @@ init_md_reader_args (argc, argv) dirtmp = (struct file_name_list *) xmalloc (sizeof (struct file_name_list)); dirtmp->next = 0; /* New one goes on the end */ - if (include == 0) - include = dirtmp; + if (first_dir_md_include == 0) + first_dir_md_include = dirtmp; else - last_include->next = dirtmp; - last_include = dirtmp; /* Tail follows the last one */ + last_dir_md_include->next = dirtmp; + last_dir_md_include = dirtmp; /* Tail follows the last one */ if (argv[i][1] == 'I' && argv[i][2] != 0) dirtmp->fname = argv[i] + 2; else if (i + 1 == argc) @@ -1013,14 +931,12 @@ init_md_reader (filename) { FILE *input_file; int c; + size_t i; char *lastsl; - if (!IS_ABSOLUTE_PATHNAME (filename)) - { - lastsl = strrchr (filename, '/'); - if (lastsl != NULL) - base_dir = save_string (filename, lastsl - filename + 1 ); - } + lastsl = strrchr (filename, '/'); + if (lastsl != NULL) + base_dir = save_string (filename, lastsl - filename + 1 ); read_rtx_filename = filename; input_file = fopen (filename, "r"); @@ -1030,6 +946,14 @@ init_md_reader (filename) return FATAL_EXIT_CODE; } + /* Initialize the table of insn conditions. */ + condition_table = htab_create (n_insn_conditions, + hash_c_test, cmp_c_test, NULL); + + for (i = 0; i < n_insn_conditions; i++) + *(htab_find_slot (condition_table, (PTR) &insn_conditions[i], INSERT)) + = (PTR) &insn_conditions[i]; + obstack_init (rtl_obstack); errors = 0; sequence_num = 0; @@ -1068,6 +992,8 @@ read_md_rtx (lineno, seqnr) struct queue_elem **queue, *elem; rtx desc; + discard: + /* Read all patterns from a given queue before moving on to the next. */ if (define_attr_queue != NULL) queue = &define_attr_queue; @@ -1081,19 +1007,35 @@ read_md_rtx (lineno, seqnr) elem = *queue; *queue = elem->next; desc = elem->data; + read_rtx_filename = elem->filename; *lineno = elem->lineno; *seqnr = sequence_num; free (elem); + /* Discard insn patterns which we know can never match (because + their C test is provably always false). If insn_elision is + false, our caller needs to see all the patterns. Note that the + elided patterns are never counted by the sequence numbering; it + it is the caller's responsibility, when insn_elision is false, not + to use elided pattern numbers for anything. */ switch (GET_CODE (desc)) { case DEFINE_INSN: case DEFINE_EXPAND: + if (maybe_eval_c_test (XSTR (desc, 2)) != 0) + sequence_num++; + else if (insn_elision) + goto discard; + break; + case DEFINE_SPLIT: case DEFINE_PEEPHOLE: case DEFINE_PEEPHOLE2: - sequence_num++; + if (maybe_eval_c_test (XSTR (desc, 1)) != 0) + sequence_num++; + else if (insn_elision) + goto discard; break; default: @@ -1102,3 +1044,118 @@ read_md_rtx (lineno, seqnr) return desc; } + +/* Helper functions for insn elision. */ + +/* Compute a hash function of a c_test structure, which is keyed + by its ->expr field. */ +hashval_t +hash_c_test (x) + const PTR x; +{ + const struct c_test *a = (const struct c_test *) x; + const unsigned char *base, *s = (const unsigned char *) a->expr; + hashval_t hash; + unsigned char c; + unsigned int len; + + base = s; + hash = 0; + + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + } + + len = s - base; + hash += len + (len << 17); + hash ^= hash >> 2; + + return hash; +} + +/* Compare two c_test expression structures. */ +int +cmp_c_test (x, y) + const PTR x; + const PTR y; +{ + const struct c_test *a = (const struct c_test *) x; + const struct c_test *b = (const struct c_test *) y; + + return !strcmp (a->expr, b->expr); +} + +/* Given a string representing a C test expression, look it up in the + condition_table and report whether or not its value is known + at compile time. Returns a tristate: 1 for known true, 0 for + known false, -1 for unknown. */ +int +maybe_eval_c_test (expr) + const char *expr; +{ + const struct c_test *test; + struct c_test dummy; + + if (expr[0] == 0) + return 1; + + if (insn_elision_unavailable) + return -1; + + dummy.expr = expr; + test = (const struct c_test *) htab_find (condition_table, &dummy); + if (!test) + abort (); + + return test->value; +} + +/* Given a string, return the number of comma-separated elements in it. + Return 0 for the null string. */ +int +n_comma_elts (s) + const char *s; +{ + int n; + + if (*s == '\0') + return 0; + + for (n = 1; *s; s++) + if (*s == ',') + n++; + + return n; +} + +/* Given a pointer to a (char *), return a pointer to the beginning of the + next comma-separated element in the string. Advance the pointer given + to the end of that element. Return NULL if at end of string. Caller + is responsible for copying the string if necessary. White space between + a comma and an element is ignored. */ + +const char * +scan_comma_elt (pstr) + const char **pstr; +{ + const char *start; + const char *p = *pstr; + + if (*p == ',') + p++; + while (ISSPACE(*p)) + p++; + + if (*p == '\0') + return NULL; + + start = p; + + while (*p != ',' && *p != '\0') + p++; + + *pstr = p; + return start; +} |