/* Support routines for the various generation passes.
- Copyright (C) 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 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)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
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
+ <http://www.gnu.org/licenses/>. */
#include "bconfig.h"
#include "system.h"
#include "obstack.h"
#include "errors.h"
#include "hashtab.h"
+#include "read-md.h"
#include "gensupport.h"
struct obstack *rtl_obstack = &obstack;
static int sequence_num;
-static int errors;
static int predicable_default;
static const char *predicable_true;
static htab_t condition_table;
-static char *base_dir = NULL;
-
/* We initially queue all patterns, process the define_insn and
define_cond_exec patterns, then return them one at a time. */
static struct queue_elem *define_attr_queue;
static struct queue_elem **define_attr_tail = &define_attr_queue;
+static struct queue_elem *define_pred_queue;
+static struct queue_elem **define_pred_tail = &define_pred_queue;
static struct queue_elem *define_insn_queue;
static struct queue_elem **define_insn_tail = &define_insn_queue;
static struct queue_elem *define_cond_exec_queue;
static struct queue_elem *queue_pattern (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.) */
-
-size_t max_include_len;
-
-struct file_name_list
- {
- struct file_name_list *next;
- const char *fname;
- };
-
-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_dir_md_include = 0; /* Last in chain */
-
static void remove_constraints (rtx);
static void process_rtx (rtx, int);
int, int);
static void process_one_cond_exec (struct queue_elem *);
static void process_define_cond_exec (void);
-static void process_include (rtx, int);
-static char *save_string (const char *, int);
+static void init_predicate_table (void);
+static void record_insn_name (int, const char *);
\f
-void
-message_with_line (int lineno, const char *msg, ...)
-{
- va_list ap;
-
- va_start (ap, msg);
-
- fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno);
- vfprintf (stderr, msg, ap);
- fputc ('\n', stderr);
-
- va_end (ap);
-}
-
/* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
the gensupport programs. */
queue_pattern (rtx pattern, struct queue_elem ***list_tail,
const char *filename, int lineno)
{
- struct queue_elem *e = xmalloc (sizeof (*e));
+ struct queue_elem *e = XNEW(struct queue_elem);
e->data = pattern;
e->filename = filename;
e->lineno = lineno;
}
}
-/* Process an include file assuming that it lives in gcc/config/{target}/
- if the include looks like (include "file"). */
-
-static void
-process_include (rtx desc, int lineno)
-{
- const char *filename = XSTR (desc, 0);
- const char *old_filename;
- int old_lineno;
- char *pathname;
- FILE *input_file;
-
- /* If specified file name is absolute, skip the include stack. */
- if (! IS_ABSOLUTE_PATH (filename))
- {
- struct file_name_list *stackp;
-
- /* Search directory path, trying to open the file. */
- for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
- {
- 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);
- }
- }
-
- 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:
-
- /* 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;
-
- /* Read the entire file. */
- while (1)
- {
- rtx desc;
- int c;
-
- 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);
- }
-
- /* Do not free pathname. It is attached to the various rtx queue
- elements. */
-
- read_rtx_filename = old_filename;
- read_rtx_lineno = old_lineno;
-
- fclose (input_file);
-}
-
/* Process a top level rtx in some way, queuing as appropriate. */
static void
switch (GET_CODE (desc))
{
case DEFINE_INSN:
- queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno);
+ queue_pattern (desc, &define_insn_tail, read_md_filename, lineno);
break;
case DEFINE_COND_EXEC:
- queue_pattern (desc, &define_cond_exec_tail, read_rtx_filename, lineno);
+ queue_pattern (desc, &define_cond_exec_tail, read_md_filename, lineno);
break;
case DEFINE_ATTR:
- queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
+ case DEFINE_ENUM_ATTR:
+ queue_pattern (desc, &define_attr_tail, read_md_filename, lineno);
break;
- case INCLUDE:
- process_include (desc, lineno);
+ case DEFINE_PREDICATE:
+ case DEFINE_SPECIAL_PREDICATE:
+ case DEFINE_CONSTRAINT:
+ case DEFINE_REGISTER_CONSTRAINT:
+ case DEFINE_MEMORY_CONSTRAINT:
+ case DEFINE_ADDRESS_CONSTRAINT:
+ queue_pattern (desc, &define_pred_tail, read_md_filename, lineno);
break;
case DEFINE_INSN_AND_SPLIT:
insn condition to create the new split condition. */
split_cond = XSTR (desc, 4);
if (split_cond[0] == '&' && split_cond[1] == '&')
- split_cond = concat (XSTR (desc, 2), split_cond, NULL);
+ {
+ copy_md_ptr_loc (split_cond + 2, split_cond);
+ split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
+ }
XSTR (split, 1) = split_cond;
XVEC (split, 2) = XVEC (desc, 5);
XSTR (split, 3) = XSTR (desc, 6);
/* Queue them. */
insn_elem
- = queue_pattern (desc, &define_insn_tail, read_rtx_filename,
+ = queue_pattern (desc, &define_insn_tail, read_md_filename,
lineno);
split_elem
- = queue_pattern (split, &other_tail, read_rtx_filename, lineno);
+ = queue_pattern (split, &other_tail, read_md_filename, lineno);
insn_elem->split = split_elem;
break;
}
default:
- queue_pattern (desc, &other_tail, read_rtx_filename, lineno);
+ queue_pattern (desc, &other_tail, read_md_filename, lineno);
break;
}
}
case SET_ATTR_ALTERNATIVE:
if (strcmp (XSTR (sub, 0), "predicable") == 0)
{
- message_with_line (elem->lineno,
- "multiple alternatives for `predicable'");
- errors = 1;
+ error_with_line (elem->lineno,
+ "multiple alternatives for `predicable'");
return 0;
}
break;
/* ??? It would be possible to handle this if we really tried.
It's not easy though, and I'm not going to bother until it
really proves necessary. */
- message_with_line (elem->lineno,
- "non-constant value for `predicable'");
- errors = 1;
+ error_with_line (elem->lineno,
+ "non-constant value for `predicable'");
return 0;
default:
- abort ();
+ gcc_unreachable ();
}
}
to do this. Delay this until we've got the basics solid. */
if (strchr (value, ',') != NULL)
{
- message_with_line (elem->lineno,
- "multiple alternatives for `predicable'");
- errors = 1;
+ error_with_line (elem->lineno, "multiple alternatives for `predicable'");
return 0;
}
if (strcmp (value, predicable_false) == 0)
return 0;
- message_with_line (elem->lineno,
- "unknown value `%s' for `predicable' attribute",
- value);
- errors = 1;
+ error_with_line (elem->lineno,
+ "unknown value `%s' for `predicable' attribute", value);
return 0;
}
if (strcmp (XSTR (elem->data, 0), "predicable") == 0)
goto found;
- message_with_line (define_cond_exec_queue->lineno,
- "attribute `predicable' not defined");
- errors = 1;
+ error_with_line (define_cond_exec_queue->lineno,
+ "attribute `predicable' not defined");
return;
found:
p_true = strchr (p_false, ',');
if (p_true == NULL || strchr (++p_true, ',') != NULL)
{
- message_with_line (elem->lineno,
- "attribute `predicable' is not a boolean");
- errors = 1;
+ error_with_line (elem->lineno, "attribute `predicable' is not a boolean");
+ if (p_false)
+ free (p_false);
return;
}
p_true[-1] = '\0';
break;
case CONST:
- message_with_line (elem->lineno,
- "attribute `predicable' cannot be const");
- errors = 1;
+ error_with_line (elem->lineno, "attribute `predicable' cannot be const");
+ if (p_false)
+ free (p_false);
return;
default:
- message_with_line (elem->lineno,
- "attribute `predicable' must have a constant default");
- errors = 1;
+ error_with_line (elem->lineno,
+ "attribute `predicable' must have a constant default");
+ if (p_false)
+ free (p_false);
return;
}
predicable_default = 0;
else
{
- message_with_line (elem->lineno,
- "unknown value `%s' for `predicable' attribute",
- value);
- errors = 1;
+ error_with_line (elem->lineno,
+ "unknown value `%s' for `predicable' attribute", value);
+ if (p_false)
+ free (p_false);
}
}
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
}
if (n_alternatives (c) != 1)
{
- message_with_line (lineno,
- "too many alternatives for operand %d",
- XINT (pattern, 0));
- errors = 1;
+ error_with_line (lineno, "too many alternatives for operand %d",
+ XINT (pattern, 0));
return NULL;
}
{
size_t c_len = strlen (c);
size_t len = alt * (c_len + 1);
- char *new_c = xmalloc (len);
+ char *new_c = XNEWVEC(char, len);
memcpy (new_c, c, c_len);
for (i = 1; i < alt; ++i)
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
alter_test_for_insn (struct queue_elem *ce_elem,
struct queue_elem *insn_elem)
{
- const char *ce_test, *insn_test;
-
- ce_test = XSTR (ce_elem->data, 1);
- insn_test = XSTR (insn_elem->data, 2);
- if (!ce_test || *ce_test == '\0')
- return insn_test;
- if (!insn_test || *insn_test == '\0')
- return ce_test;
-
- return concat ("(", ce_test, ") && (", insn_test, ")", NULL);
+ return join_c_conditions (XSTR (ce_elem->data, 1),
+ XSTR (insn_elem->data, 2));
}
-/* Adjust all of the operand numbers in OLD to match the shift they'll
+/* Adjust all of the operand numbers in SRC to match the shift they'll
get from an operand displacement of DISP. Return a pointer after the
adjusted string. */
static char *
-shift_output_template (char *dest, const char *old, int disp)
+shift_output_template (char *dest, const char *src, int disp)
{
- while (*old)
+ while (*src)
{
- char c = *old++;
+ char c = *src++;
*dest++ = c;
if (c == '%')
{
- c = *old++;
+ c = *src++;
if (ISDIGIT ((unsigned char) c))
c += disp;
else if (ISALPHA (c))
{
*dest++ = c;
- c = *old++ + disp;
+ c = *src++ + disp;
}
*dest++ = c;
}
{
int alternatives, max_operand;
rtx pred, insn, pattern, split;
+ char *new_name;
int i;
if (! is_predicable (insn_elem))
if (XVECLEN (ce_elem->data, 0) != 1)
{
- message_with_line (ce_elem->lineno,
- "too many patterns in predicate");
- errors = 1;
+ error_with_line (ce_elem->lineno, "too many patterns in predicate");
return;
}
/* Construct a new pattern for the new insn. */
insn = copy_rtx (insn_elem->data);
- XSTR (insn, 0) = "";
+ new_name = XNEWVAR (char, strlen XSTR (insn_elem->data, 0) + 4);
+ sprintf (new_name, "*p %s", XSTR (insn_elem->data, 0));
+ XSTR (insn, 0) = new_name;
pattern = rtx_alloc (COND_EXEC);
XEXP (pattern, 0) = pred;
if (XVECLEN (insn, 1) == 1)
XVECEXP (split, 2, i) = pattern;
}
/* Add the new split to the queue. */
- queue_pattern (split, &other_tail, read_rtx_filename,
+ queue_pattern (split, &other_tail, read_md_filename,
insn_elem->split->lineno);
}
}
struct queue_elem *elem;
identify_predicable_attribute ();
- if (errors)
+ if (have_error)
return;
for (elem = define_cond_exec_queue; elem ; elem = elem->next)
process_one_cond_exec (elem);
}
-
-static char *
-save_string (const char *s, int len)
-{
- char *result = xmalloc (len + 1);
-
- memcpy (result, s, len);
- result[len] = 0;
- return result;
-}
-
\f
-/* The entry point for initializing the reader. */
+/* A read_md_files callback for reading an rtx. */
-int
-init_md_reader_args (int argc, char **argv)
+static void
+rtx_handle_directive (int lineno, const char *rtx_name)
{
- int i;
- const char *in_fname;
-
- max_include_len = 0;
- in_fname = NULL;
- for (i = 1; i < argc; i++)
- {
- if (argv[i][0] != '-')
- {
- if (in_fname == NULL)
- in_fname = argv[i];
- }
- else
- {
- int c = argv[i][1];
- switch (c)
- {
- case 'I': /* Add directory to path for includes. */
- {
- struct file_name_list *dirtmp;
-
- dirtmp = xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- if (first_dir_md_include == 0)
- first_dir_md_include = dirtmp;
- else
- 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)
- fatal ("directory name missing after -I option");
- else
- dirtmp->fname = argv[++i];
- if (strlen (dirtmp->fname) > max_include_len)
- max_include_len = strlen (dirtmp->fname);
- }
- break;
- default:
- fatal ("invalid option `%s'", argv[i]);
+ rtx queue, x;
- }
- }
- }
- return init_md_reader (in_fname);
+ if (read_rtx (rtx_name, &queue))
+ for (x = queue; x; x = XEXP (x, 1))
+ process_rtx (XEXP (x, 0), lineno);
}
-\f
+
/* The entry point for initializing the reader. */
-int
-init_md_reader (const char *filename)
+bool
+init_rtx_reader_args_cb (int argc, char **argv,
+ bool (*parse_opt) (const char *))
{
- FILE *input_file;
- int c;
- size_t i;
- char *lastsl;
-
- lastsl = strrchr (filename, '/');
- if (lastsl != NULL)
- base_dir = save_string (filename, lastsl - filename + 1 );
-
- read_rtx_filename = filename;
- input_file = fopen (filename, "r");
- if (input_file == 0)
- {
- perror (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, &insn_conditions[i], INSERT))
- = (void *) &insn_conditions[i];
-
+ /* Prepare to read input. */
+ condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL);
+ init_predicate_table ();
obstack_init (rtl_obstack);
- errors = 0;
sequence_num = 0;
- /* Read the entire file. */
- while (1)
- {
- rtx desc;
- int lineno;
-
- 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);
- }
- fclose (input_file);
+ read_md_files (argc, argv, parse_opt, rtx_handle_directive);
/* Process define_cond_exec patterns. */
if (define_cond_exec_queue != NULL)
process_define_cond_exec ();
- return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
+ return !have_error;
}
+/* Programs that don't have their own options can use this entry point
+ instead. */
+bool
+init_rtx_reader_args (int argc, char **argv)
+{
+ return init_rtx_reader_args_cb (argc, argv, 0);
+}
+\f
/* The entry point for reading a single rtx from an md file. */
rtx
/* Read all patterns from a given queue before moving on to the next. */
if (define_attr_queue != NULL)
queue = &define_attr_queue;
+ else if (define_pred_queue != NULL)
+ queue = &define_pred_queue;
else if (define_insn_queue != NULL)
queue = &define_insn_queue;
else if (other_queue != NULL)
elem = *queue;
*queue = elem->next;
desc = elem->data;
- read_rtx_filename = elem->filename;
+ read_md_filename = elem->filename;
*lineno = elem->lineno;
*seqnr = sequence_num;
sequence_num++;
else if (insn_elision)
goto discard;
+
+ /* *seqnr is used here so the name table will match caller's
+ idea of insn numbering, whether or not elision is active. */
+ record_insn_name (*seqnr, XSTR (desc, 0));
break;
case DEFINE_SPLIT:
if (expr[0] == 0)
return 1;
- if (insn_elision_unavailable)
- return -1;
-
dummy.expr = expr;
- test = htab_find (condition_table, &dummy);
+ test = (const struct c_test *)htab_find (condition_table, &dummy);
if (!test)
- abort ();
-
+ return -1;
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 (const char *s)
+/* Record the C test expression EXPR in the condition_table, with
+ value VAL. Duplicates clobber previous entries. */
+
+void
+add_c_test (const char *expr, int value)
{
- int n;
+ struct c_test *test;
- if (*s == '\0')
- return 0;
+ if (expr[0] == 0)
+ return;
- for (n = 1; *s; s++)
- if (*s == ',')
- n++;
+ test = XNEW (struct c_test);
+ test->expr = expr;
+ test->value = value;
- return n;
+ *(htab_find_slot (condition_table, test, INSERT)) = test;
}
-/* 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. */
+/* For every C test, call CALLBACK with two arguments: a pointer to
+ the condition structure and INFO. Stops when CALLBACK returns zero. */
+void
+traverse_c_tests (htab_trav callback, void *info)
+{
+ if (condition_table)
+ htab_traverse (condition_table, callback, info);
+}
-const char *
-scan_comma_elt (const char **pstr)
+/* Helper functions for define_predicate and define_special_predicate
+ processing. Shared between genrecog.c and genpreds.c. */
+
+static htab_t predicate_table;
+struct pred_data *first_predicate;
+static struct pred_data **last_predicate = &first_predicate;
+
+static hashval_t
+hash_struct_pred_data (const void *ptr)
+{
+ return htab_hash_string (((const struct pred_data *)ptr)->name);
+}
+
+static int
+eq_struct_pred_data (const void *a, const void *b)
{
- const char *start;
- const char *p = *pstr;
+ return !strcmp (((const struct pred_data *)a)->name,
+ ((const struct pred_data *)b)->name);
+}
- if (*p == ',')
- p++;
- while (ISSPACE(*p))
- p++;
+struct pred_data *
+lookup_predicate (const char *name)
+{
+ struct pred_data key;
+ key.name = name;
+ return (struct pred_data *) htab_find (predicate_table, &key);
+}
- if (*p == '\0')
+/* Record that predicate PRED can accept CODE. */
+
+void
+add_predicate_code (struct pred_data *pred, enum rtx_code code)
+{
+ if (!pred->codes[code])
+ {
+ pred->num_codes++;
+ pred->codes[code] = true;
+
+ if (GET_RTX_CLASS (code) != RTX_CONST_OBJ)
+ pred->allows_non_const = true;
+
+ if (code != REG
+ && code != SUBREG
+ && code != MEM
+ && code != CONCAT
+ && code != PARALLEL
+ && code != STRICT_LOW_PART)
+ pred->allows_non_lvalue = true;
+
+ if (pred->num_codes == 1)
+ pred->singleton = code;
+ else if (pred->num_codes == 2)
+ pred->singleton = UNKNOWN;
+ }
+}
+
+void
+add_predicate (struct pred_data *pred)
+{
+ void **slot = htab_find_slot (predicate_table, pred, INSERT);
+ if (*slot)
+ {
+ error ("duplicate predicate definition for '%s'", pred->name);
+ return;
+ }
+ *slot = pred;
+ *last_predicate = pred;
+ last_predicate = &pred->next;
+}
+
+/* This array gives the initial content of the predicate table. It
+ has entries for all predicates defined in recog.c. */
+
+struct std_pred_table
+{
+ const char *name;
+ bool special;
+ bool allows_const_p;
+ RTX_CODE codes[NUM_RTX_CODE];
+};
+
+static const struct std_pred_table std_preds[] = {
+ {"general_operand", false, true, {SUBREG, REG, MEM}},
+ {"address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}},
+ {"register_operand", false, false, {SUBREG, REG}},
+ {"pmode_register_operand", true, false, {SUBREG, REG}},
+ {"scratch_operand", false, false, {SCRATCH, REG}},
+ {"immediate_operand", false, true, {UNKNOWN}},
+ {"const_int_operand", false, false, {CONST_INT}},
+ {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+ {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
+ {"nonmemory_operand", false, true, {SUBREG, REG}},
+ {"push_operand", false, false, {MEM}},
+ {"pop_operand", false, false, {MEM}},
+ {"memory_operand", false, false, {SUBREG, MEM}},
+ {"indirect_operand", false, false, {SUBREG, MEM}},
+ {"ordered_comparison_operator", false, false, {EQ, NE,
+ LE, LT, GE, GT,
+ LEU, LTU, GEU, GTU}},
+ {"comparison_operator", false, false, {EQ, NE,
+ LE, LT, GE, GT,
+ LEU, LTU, GEU, GTU,
+ UNORDERED, ORDERED,
+ UNEQ, UNGE, UNGT,
+ UNLE, UNLT, LTGT}}
+};
+#define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds)
+
+/* Initialize the table of predicate definitions, starting with
+ the information we have on generic predicates. */
+
+static void
+init_predicate_table (void)
+{
+ size_t i, j;
+ struct pred_data *pred;
+
+ predicate_table = htab_create_alloc (37, hash_struct_pred_data,
+ eq_struct_pred_data, 0,
+ xcalloc, free);
+
+ for (i = 0; i < NUM_KNOWN_STD_PREDS; i++)
+ {
+ pred = XCNEW (struct pred_data);
+ pred->name = std_preds[i].name;
+ pred->special = std_preds[i].special;
+
+ for (j = 0; std_preds[i].codes[j] != 0; j++)
+ add_predicate_code (pred, std_preds[i].codes[j]);
+
+ if (std_preds[i].allows_const_p)
+ for (j = 0; j < NUM_RTX_CODE; j++)
+ if (GET_RTX_CLASS (j) == RTX_CONST_OBJ)
+ add_predicate_code (pred, (enum rtx_code) j);
+
+ add_predicate (pred);
+ }
+}
+\f
+/* These functions allow linkage with print-rtl.c. Also, some generators
+ like to annotate their output with insn names. */
+
+/* Holds an array of names indexed by insn_code_number. */
+static char **insn_name_ptr = 0;
+static int insn_name_ptr_size = 0;
+
+const char *
+get_insn_name (int code)
+{
+ if (code < insn_name_ptr_size)
+ return insn_name_ptr[code];
+ else
return NULL;
+}
+
+static void
+record_insn_name (int code, const char *name)
+{
+ static const char *last_real_name = "insn";
+ static int last_real_code = 0;
+ char *new_name;
- start = p;
+ if (insn_name_ptr_size <= code)
+ {
+ int new_size;
+ new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
+ insn_name_ptr = XRESIZEVEC (char *, insn_name_ptr, new_size);
+ memset (insn_name_ptr + insn_name_ptr_size, 0,
+ sizeof(char *) * (new_size - insn_name_ptr_size));
+ insn_name_ptr_size = new_size;
+ }
- while (*p != ',' && *p != '\0')
- p++;
+ if (!name || name[0] == '\0')
+ {
+ new_name = XNEWVAR (char, strlen (last_real_name) + 10);
+ sprintf (new_name, "%s+%d", last_real_name, code - last_real_code);
+ }
+ else
+ {
+ last_real_name = new_name = xstrdup (name);
+ last_real_code = code;
+ }
- *pstr = p;
- return start;
+ insn_name_ptr[code] = new_name;
}