/* Support routines for the various generation passes.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
- 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, 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, 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"
int insn_elision = 1;
-const char *in_fname;
-
-/* This callback will be invoked whenever an rtl include directive is
- processed. To be used for creation of the dependency file. */
-void (*include_callback) (const char *);
-
static struct obstack obstack;
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 *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. */
}
}
-/* 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;
-
- if (include_callback)
- include_callback (pathname);
-
- /* Read the entire file. */
- while (read_rtx (input_file, &desc, &lineno))
- 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 DEFINE_PREDICATE:
case DEFINE_SPECIAL_PREDICATE:
- queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno);
- break;
-
- case INCLUDE:
- process_include (desc, lineno);
+ 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:
split_cond = XSTR (desc, 4);
if (split_cond[0] == '&' && split_cond[1] == '&')
{
- copy_rtx_ptr_loc (split_cond + 2, split_cond);
+ 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;
/* 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:
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);
}
}
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;
}
{
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);
}
+\f
+/* A read_md_files callback for reading an rtx. */
-static char *
-save_string (const char *s, int len)
+static void
+rtx_handle_directive (int lineno, const char *rtx_name)
{
- char *result = XNEWVEC (char, len + 1);
+ rtx queue, x;
- memcpy (result, s, len);
- result[len] = 0;
- return result;
+ 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_args_cb (int argc, char **argv, bool (*parse_opt)(const char *))
+bool
+init_rtx_reader_args_cb (int argc, char **argv,
+ bool (*parse_opt) (const char *))
{
- FILE *input_file;
- int i, lineno;
- size_t ix;
- char *lastsl;
- rtx desc;
-
- /* Unlock the stdio streams. */
- unlock_std_streams ();
-
- for (i = 1; i < argc; i++)
- {
- if (argv[i][0] != '-')
- {
- if (in_fname)
- fatal ("too many input files");
-
- 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 = XNEW (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:
- /* The program may have provided a callback so it can
- accept its own options. */
- if (parse_opt && parse_opt (argv[i]))
- break;
-
- fatal ("invalid option `%s'", argv[i]);
- }
- }
- }
-
- if (!in_fname)
- fatal ("no input file name");
-
- lastsl = strrchr (in_fname, '/');
- if (lastsl != NULL)
- base_dir = save_string (in_fname, lastsl - in_fname + 1 );
-
- read_rtx_filename = in_fname;
- input_file = fopen (in_fname, "r");
- if (input_file == 0)
- {
- perror (in_fname);
- 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 (ix = 0; ix < n_insn_conditions; ix++)
- *(htab_find_slot (condition_table, &insn_conditions[ix], INSERT))
- = (void *) &insn_conditions[ix];
-
+ /* 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 (read_rtx (input_file, &desc, &lineno))
- 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. */
-int
-init_md_reader_args (int argc, char **argv)
+bool
+init_rtx_reader_args (int argc, char **argv)
{
- return init_md_reader_args_cb (argc, argv, 0);
+ return init_rtx_reader_args_cb (argc, argv, 0);
}
\f
/* The entry point for reading a single rtx from an md file. */
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 = (const struct c_test *)htab_find (condition_table, &dummy);
- gcc_assert (test);
-
+ if (!test)
+ 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. */
-
-const char *
-scan_comma_elt (const char **pstr)
+/* 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)
{
- 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;
+ if (condition_table)
+ htab_traverse (condition_table, callback, info);
}
/* Helper functions for define_predicate and define_special_predicate
{
struct pred_data key;
key.name = name;
- return htab_find (predicate_table, &key);
+ return (struct pred_data *) htab_find (predicate_table, &key);
+}
+
+/* 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
}
/* This array gives the initial content of the predicate table. It
- has entries for all predicates defined in recog.c. The back end
- can define PREDICATE_CODES to give additional entries for the
- table; this is considered an obsolete mechanism (use
- define_predicate instead). */
+ has entries for all predicates defined in recog.c. */
-struct old_pred_table
+struct std_pred_table
{
const char *name;
+ bool special;
+ bool allows_const_p;
RTX_CODE codes[NUM_RTX_CODE];
};
-static const struct old_pred_table old_preds[] = {
- {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF, SUBREG, REG, MEM }},
- {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF, SUBREG, REG, MEM,
- PLUS, MINUS, MULT}},
- {"register_operand", {SUBREG, REG}},
- {"pmode_register_operand", {SUBREG, REG}},
- {"scratch_operand", {SCRATCH, REG}},
- {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF}},
- {"const_int_operand", {CONST_INT}},
- {"const_double_operand", {CONST_INT, CONST_DOUBLE}},
- {"nonimmediate_operand", {SUBREG, REG, MEM}},
- {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF, SUBREG, REG}},
- {"push_operand", {MEM}},
- {"pop_operand", {MEM}},
- {"memory_operand", {SUBREG, MEM}},
- {"indirect_operand", {SUBREG, MEM}},
- {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
- UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
- UNLT, LTGT}},
-#ifdef PREDICATE_CODES
- PREDICATE_CODES
-#endif
+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_OLD_PREDS ARRAY_SIZE (old_preds)
-
-/* This table gives the initial set of special predicates. It has
- entries for all special predicates defined in recog.c. The back
- end can define SPECIAL_MODE_PREDICATES to give additional entries
- for the table; this is considered an obsolete mechanism (use
- define_special_predicate instead). */
-static const char *const old_special_pred_table[] = {
- "address_operand",
- "pmode_register_operand",
-#ifdef SPECIAL_MODE_PREDICATES
- SPECIAL_MODE_PREDICATES
-#endif
-};
-
-#define NUM_OLD_SPECIAL_MODE_PREDS ARRAY_SIZE (old_special_pred_table)
+#define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds)
/* Initialize the table of predicate definitions, starting with
- the information we have on generic predicates, and the old-style
- PREDICATE_CODES definitions. */
+ the information we have on generic predicates. */
static void
init_predicate_table (void)
eq_struct_pred_data, 0,
xcalloc, free);
- for (i = 0; i < NUM_KNOWN_OLD_PREDS; i++)
+ for (i = 0; i < NUM_KNOWN_STD_PREDS; i++)
{
- pred = xcalloc (sizeof (struct pred_data), 1);
- pred->name = old_preds[i].name;
+ 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);
- for (j = 0; old_preds[i].codes[j] != 0; j++)
- {
- enum rtx_code code = old_preds[i].codes[j];
-
- 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 (j == 1)
- pred->singleton = old_preds[i].codes[0];
-
add_predicate (pred);
}
+}
+\f
+/* These functions allow linkage with print-rtl.c. Also, some generators
+ like to annotate their output with insn names. */
- for (i = 0; i < NUM_OLD_SPECIAL_MODE_PREDS; i++)
+/* 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;
+
+ if (insn_name_ptr_size <= code)
{
- pred = lookup_predicate (old_special_pred_table[i]);
- if (!pred)
- {
- error ("old-style special predicate list refers "
- "to unknown predicate '%s'", old_special_pred_table[i]);
- continue;
- }
- pred->special = true;
+ 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;
}
+
+ 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;
+ }
+
+ insn_name_ptr[code] = new_name;
}