/* Support routines for the various generation passes.
- Copyright (C) 2000-2016 Free Software Foundation, Inc.
+ Copyright (C) 2000-2020 Free Software Foundation, Inc.
This file is part of GCC.
define_cond_exec and define_subst patterns, then return
them one at a time. */
-struct queue_elem
+class queue_elem
{
+public:
rtx data;
file_location loc;
- struct queue_elem *next;
- /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT, SPLIT
- points to the generated DEFINE_SPLIT. */
- struct queue_elem *split;
+ class queue_elem *next;
+ /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT or
+ DEFINE_INSN_AND_REWRITE, SPLIT points to the generated DEFINE_SPLIT. */
+ class queue_elem *split;
};
#define MNEMONIC_ATTR_NAME "mnemonic"
#define MNEMONIC_HTAB_SIZE 1024
-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 **define_cond_exec_tail = &define_cond_exec_queue;
-static struct queue_elem *define_subst_queue;
-static struct queue_elem **define_subst_tail = &define_subst_queue;
-static struct queue_elem *other_queue;
-static struct queue_elem **other_tail = &other_queue;
-static struct queue_elem *define_subst_attr_queue;
-static struct queue_elem **define_subst_attr_tail = &define_subst_attr_queue;
+static class queue_elem *define_attr_queue;
+static class queue_elem **define_attr_tail = &define_attr_queue;
+static class queue_elem *define_pred_queue;
+static class queue_elem **define_pred_tail = &define_pred_queue;
+static class queue_elem *define_insn_queue;
+static class queue_elem **define_insn_tail = &define_insn_queue;
+static class queue_elem *define_cond_exec_queue;
+static class queue_elem **define_cond_exec_tail = &define_cond_exec_queue;
+static class queue_elem *define_subst_queue;
+static class queue_elem **define_subst_tail = &define_subst_queue;
+static class queue_elem *other_queue;
+static class queue_elem **other_tail = &other_queue;
+static class queue_elem *define_subst_attr_queue;
+static class queue_elem **define_subst_attr_tail = &define_subst_attr_queue;
/* Mapping from DEFINE_* rtxes to their location in the source file. */
static hash_map <rtx, file_location> *rtx_locs;
static void remove_constraints (rtx);
-static int is_predicable (struct queue_elem *);
+static int is_predicable (class queue_elem *);
static void identify_predicable_attribute (void);
static int n_alternatives (const char *);
static void collect_insn_data (rtx, int *, int *);
-static const char *alter_test_for_insn (struct queue_elem *,
- struct queue_elem *);
+static const char *alter_test_for_insn (class queue_elem *,
+ class queue_elem *);
static char *shift_output_template (char *, const char *, int);
-static const char *alter_output_for_insn (struct queue_elem *,
- struct queue_elem *,
+static const char *alter_output_for_insn (class queue_elem *,
+ class queue_elem *,
int, int);
-static void process_one_cond_exec (struct queue_elem *);
+static void process_one_cond_exec (class queue_elem *);
static void process_define_cond_exec (void);
static void init_predicate_table (void);
static void record_insn_name (int, const char *);
-static bool has_subst_attribute (struct queue_elem *, struct queue_elem *);
+static bool has_subst_attribute (class queue_elem *, class queue_elem *);
static const char * alter_output_for_subst_insn (rtx, int);
-static void alter_attrs_for_subst_insn (struct queue_elem *, int);
-static void process_substs_on_one_elem (struct queue_elem *,
- struct queue_elem *);
+static void alter_attrs_for_subst_insn (class queue_elem *, int);
+static void process_substs_on_one_elem (class queue_elem *,
+ class queue_elem *);
static rtx subst_dup (rtx, int, int);
static void process_define_subst (void);
/* Queue PATTERN on LIST_TAIL. Return the address of the new queue
element. */
-static struct queue_elem *
-queue_pattern (rtx pattern, struct queue_elem ***list_tail,
+static class queue_elem *
+queue_pattern (rtx pattern, class queue_elem ***list_tail,
file_location loc)
{
- struct queue_elem *e = XNEW (struct queue_elem);
+ class queue_elem *e = XNEW (class queue_elem);
e->data = pattern;
e->loc = loc;
e->next = NULL;
/* Remove element ELEM from QUEUE. */
static void
-remove_from_queue (struct queue_elem *elem, struct queue_elem **queue)
+remove_from_queue (class queue_elem *elem, class queue_elem **queue)
{
- struct queue_elem *prev, *e;
+ class queue_elem *prev, *e;
prev = NULL;
for (e = *queue; e ; e = e->next)
{
static void
add_define_attr (const char *name)
{
- struct queue_elem *e = XNEW (struct queue_elem);
+ class queue_elem *e = XNEW (class queue_elem);
rtx t1 = rtx_alloc (DEFINE_ATTR);
XSTR (t1, 0) = name;
XSTR (t1, 1) = "no,yes";
XEXP (t1, 2) = rtx_alloc (CONST_STRING);
XSTR (XEXP (t1, 2), 0) = "yes";
e->data = t1;
- e->loc = file_location ("built-in", -1);
+ e->loc = file_location ("built-in", -1, -1);
e->next = define_attr_queue;
define_attr_queue = e;
}
}
+/* Recursively replace MATCH_OPERANDs with MATCH_DUPs and MATCH_OPERATORs
+ with MATCH_OP_DUPs in X. */
+
+static rtx
+replace_operands_with_dups (rtx x)
+{
+ if (x == 0)
+ return x;
+
+ rtx newx;
+ if (GET_CODE (x) == MATCH_OPERAND)
+ {
+ newx = rtx_alloc (MATCH_DUP);
+ XINT (newx, 0) = XINT (x, 0);
+ x = newx;
+ }
+ else if (GET_CODE (x) == MATCH_OPERATOR)
+ {
+ newx = rtx_alloc (MATCH_OP_DUP);
+ XINT (newx, 0) = XINT (x, 0);
+ XVEC (newx, 1) = XVEC (x, 2);
+ x = newx;
+ }
+ else
+ newx = shallow_copy_rtx (x);
+
+ const char *format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+ for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
+ switch (*format_ptr++)
+ {
+ case 'e':
+ case 'u':
+ XEXP (newx, i) = replace_operands_with_dups (XEXP (x, i));
+ break;
+ case 'E':
+ if (XVEC (x, i) != NULL)
+ {
+ XVEC (newx, i) = rtvec_alloc (XVECLEN (x, i));
+ for (int j = 0; j < XVECLEN (x, i); j++)
+ XVECEXP (newx, i, j)
+ = replace_operands_with_dups (XVECEXP (x, i, j));
+ }
+ break;
+ }
+ return newx;
+}
+
+/* Convert matching pattern VEC from a DEFINE_INSN_AND_REWRITE into
+ a sequence that should be generated by the splitter. */
+
+static rtvec
+gen_rewrite_sequence (rtvec vec)
+{
+ rtvec new_vec = rtvec_alloc (1);
+ rtx x = add_implicit_parallel (vec);
+ RTVEC_ELT (new_vec, 0) = replace_operands_with_dups (x);
+ return new_vec;
+}
+
/* Process a top level rtx in some way, queuing as appropriate. */
static void
case DEFINE_CONSTRAINT:
case DEFINE_REGISTER_CONSTRAINT:
case DEFINE_MEMORY_CONSTRAINT:
+ case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
case DEFINE_ADDRESS_CONSTRAINT:
queue_pattern (desc, &define_pred_tail, loc);
break;
case DEFINE_INSN_AND_SPLIT:
+ case DEFINE_INSN_AND_REWRITE:
{
const char *split_cond;
rtx split;
rtvec attr;
int i;
- struct queue_elem *insn_elem;
- struct queue_elem *split_elem;
+ class queue_elem *insn_elem;
+ class queue_elem *split_elem;
+ int split_code = (GET_CODE (desc) == DEFINE_INSN_AND_REWRITE ? 5 : 6);
/* Create a split with values from the insn_and_split. */
split = rtx_alloc (DEFINE_SPLIT);
split_cond = XSTR (desc, 4);
if (split_cond[0] == '&' && split_cond[1] == '&')
{
- copy_md_ptr_loc (split_cond + 2, split_cond);
- split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
+ rtx_reader_ptr->copy_md_ptr_loc (split_cond + 2, split_cond);
+ split_cond = rtx_reader_ptr->join_c_conditions (XSTR (desc, 2),
+ split_cond + 2);
}
+ else if (GET_CODE (desc) == DEFINE_INSN_AND_REWRITE)
+ error_at (loc, "the rewrite condition must start with `&&'");
XSTR (split, 1) = split_cond;
- XVEC (split, 2) = XVEC (desc, 5);
- XSTR (split, 3) = XSTR (desc, 6);
+ if (GET_CODE (desc) == DEFINE_INSN_AND_REWRITE)
+ XVEC (split, 2) = gen_rewrite_sequence (XVEC (desc, 1));
+ else
+ XVEC (split, 2) = XVEC (desc, 5);
+ XSTR (split, 3) = XSTR (desc, split_code);
/* Fix up the DEFINE_INSN. */
- attr = XVEC (desc, 7);
+ attr = XVEC (desc, split_code + 1);
PUT_CODE (desc, DEFINE_INSN);
XVEC (desc, 4) = attr;
a DEFINE_INSN. */
static int
-is_predicable (struct queue_elem *elem)
+is_predicable (class queue_elem *elem)
{
rtvec vec = XVEC (elem->data, 4);
const char *value;
/* Find attribute SUBST in ELEM and assign NEW_VALUE to it. */
static void
-change_subst_attribute (struct queue_elem *elem,
- struct queue_elem *subst_elem,
+change_subst_attribute (class queue_elem *elem,
+ class queue_elem *subst_elem,
const char *new_value)
{
rtvec attrs_vec = XVEC (elem->data, 4);
represented by SUBST_ELEM and this attribute has value SUBST_TRUE.
DEFINE_SUBST isn't applied to patterns without such attribute. In other
words, we suppose the default value of the attribute to be 'no' since it is
- always generated automaticaly in read-rtl.c. */
+ always generated automatically in read-rtl.c. */
static bool
-has_subst_attribute (struct queue_elem *elem, struct queue_elem *subst_elem)
+has_subst_attribute (class queue_elem *elem, class queue_elem *subst_elem)
{
rtvec attrs_vec = XVEC (elem->data, 4);
const char *value, *subst_name = XSTR (subst_elem->data, 0);
return false;
case SET_ATTR_ALTERNATIVE:
- error_at (elem->loc,
- "%s: `set_attr_alternative' is unsupported by "
- "`define_subst'", XSTR (elem->data, 0));
+ if (strcmp (XSTR (cur_attr, 0), subst_name) == 0)
+ error_at (elem->loc,
+ "%s: `set_attr_alternative' is unsupported by "
+ "`define_subst'", XSTR (elem->data, 0));
return false;
switch (fmt[i])
{
- case 'i': case 'r': case 'w': case 's':
+ case 'r': case 'p': case 'i': case 'w': case 's':
continue;
case 'e': case 'u':
static void
identify_predicable_attribute (void)
{
- struct queue_elem *elem;
+ class queue_elem *elem;
char *p_true, *p_false;
const char *value;
case 'V':
if (XVEC (pattern, i) == NULL)
break;
+ /* FALLTHRU */
case 'E':
for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
return 0;
break;
- case 'i': case 'r': case 'w': case '0': case 's': case 'S': case 'T':
+ case 'r': case 'p': case 'i': case 'w':
+ case '0': case 's': case 'S': case 'T':
break;
default:
collect_insn_data (XVECEXP (pattern, i, j), palt, pmax);
break;
- case 'i': case 'r': case 'w': case '0': case 's': case 'S': case 'T':
+ case 'r': case 'p': case 'i': case 'w':
+ case '0': case 's': case 'S': case 'T':
break;
default:
}
break;
- case 'i': case 'r': case 'w': case '0': case 's':
+ case 'r': case 'p': case 'i': case 'w': case '0': case 's':
break;
default:
}
break;
- case 'i': case 'r': case 'w': case '0': case 's':
+ case 'r': case 'p': case 'i': case 'w': case '0': case 's':
break;
default:
}
static const char *
-alter_test_for_insn (struct queue_elem *ce_elem,
- struct queue_elem *insn_elem)
+alter_test_for_insn (class queue_elem *ce_elem,
+ class queue_elem *insn_elem)
{
- return join_c_conditions (XSTR (ce_elem->data, 1),
- XSTR (insn_elem->data, 2));
+ return rtx_reader_ptr->join_c_conditions (XSTR (ce_elem->data, 1),
+ XSTR (insn_elem->data, 2));
}
/* Modify VAL, which is an attribute expression for the "enabled" attribute,
if (!global_changes_made)
{
- struct queue_elem *elem;
+ class queue_elem *elem;
global_changes_made = true;
add_define_attr ("ce_enabled");
ELEM is a queue element, containing our rtl-template,
N_DUP - multiplication factor. */
static void
-alter_attrs_for_subst_insn (struct queue_elem * elem, int n_dup)
+alter_attrs_for_subst_insn (class queue_elem * elem, int n_dup)
{
rtvec vec = XVEC (elem->data, 4);
int num_elem;
}
static const char *
-alter_output_for_insn (struct queue_elem *ce_elem,
- struct queue_elem *insn_elem,
+alter_output_for_insn (class queue_elem *ce_elem,
+ class queue_elem *insn_elem,
int alt, int max_op)
{
const char *ce_out, *insn_out;
static const char *
alter_output_for_subst_insn (rtx insn, int alt)
{
- const char *insn_out, *sp ;
- char *old_out, *new_out, *cp;
- int i, j, new_len;
+ const char *insn_out, *old_out;
+ char *new_out, *cp;
+ size_t old_len, new_len;
+ int j;
insn_out = XTMPL (insn, 3);
- if (alt < 2 || *insn_out == '*' || *insn_out != '@')
+ if (alt < 2 || *insn_out != '@')
return insn_out;
- old_out = XNEWVEC (char, strlen (insn_out)),
- sp = insn_out;
+ old_out = insn_out + 1;
+ while (ISSPACE (*old_out))
+ old_out++;
+ old_len = strlen (old_out);
- while (ISSPACE (*sp) || *sp == '@')
- sp++;
-
- for (i = 0; *sp;)
- old_out[i++] = *sp++;
-
- new_len = alt * (i + 1) + 1;
+ new_len = alt * (old_len + 1) + 1;
new_out = XNEWVEC (char, new_len);
new_out[0] = '@';
- for (j = 0, cp = new_out + 1; j < alt; j++, cp += i + 1)
+ for (j = 0, cp = new_out + 1; j < alt; j++, cp += old_len + 1)
{
- memcpy (cp, old_out, i);
- *(cp+i) = (j == alt - 1) ? '\0' : '\n';
+ memcpy (cp, old_out, old_len);
+ cp[old_len] = (j == alt - 1) ? '\0' : '\n';
}
return new_out;
/* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */
static void
-process_one_cond_exec (struct queue_elem *ce_elem)
+process_one_cond_exec (class queue_elem *ce_elem)
{
- struct queue_elem *insn_elem;
+ class queue_elem *insn_elem;
for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next)
{
int alternatives, max_operand;
was applied, ELEM would be deleted. */
static void
-process_substs_on_one_elem (struct queue_elem *elem,
- struct queue_elem *queue)
+process_substs_on_one_elem (class queue_elem *elem,
+ class queue_elem *queue)
{
- struct queue_elem *subst_elem;
+ class queue_elem *subst_elem;
int i, j, patterns_match;
for (subst_elem = define_subst_queue;
/* Recalculate condition, joining conditions from original and
DEFINE_SUBST input patterns. */
- XSTR (elem->data, 2) = join_c_conditions (XSTR (subst_elem->data, 2),
- XSTR (elem->data, 2));
+ XSTR (elem->data, 2)
+ = rtx_reader_ptr->join_c_conditions (XSTR (subst_elem->data, 2),
+ XSTR (elem->data, 2));
/* Mark that subst was applied by changing attribute from "yes"
to "no". */
change_subst_attribute (elem, subst_elem, subst_false);
case 'V':
if (XVEC (pattern, i) == NULL)
break;
+ /* FALLTHRU */
case 'E':
if (code != MATCH_DUP && code != MATCH_OP_DUP)
for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
n_alt, n_subst_alt);
break;
- case 'i': case 'r': case 'w': case '0': case 's': case 'S': case 'T':
+ case 'r': case 'p': case 'i': case 'w':
+ case '0': case 's': case 'S': case 'T':
break;
default:
static void
process_define_cond_exec (void)
{
- struct queue_elem *elem;
+ class queue_elem *elem;
identify_predicable_attribute ();
if (have_error)
static void
process_define_subst (void)
{
- struct queue_elem *elem, *elem_attr;
+ class queue_elem *elem, *elem_attr;
/* Check if each define_subst has corresponding define_subst_attr. */
for (elem = define_subst_queue; elem ; elem = elem->next)
}
}
\f
-/* A read_md_files callback for reading an rtx. */
+/* A subclass of rtx_reader which reads .md files and calls process_rtx on
+ the top-level elements. */
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+ gen_reader () : rtx_reader (false) {}
+ void handle_unknown_directive (file_location, const char *);
+};
+
+void
+gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name)
{
auto_vec<rtx, 32> subrtxs;
if (!read_rtx (rtx_name, &subrtxs))
}
/* Add mnemonic STR with length LEN to the mnemonic hash table
- MNEMONIC_HTAB. A trailing zero end character is appendend to STR
+ MNEMONIC_HTAB. A trailing zero end character is appended to STR
and a permanent heap copy of STR is created. */
static void
rtx set_attr;
char *attr_name;
rtvec new_vec;
+ struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
template_code = XTMPL (insn, 3);
sp = ep + 1;
if (i > 0)
- obstack_1grow (&string_obstack, ',');
+ obstack_1grow (string_obstack, ',');
while (cp < sp && ((*cp >= '0' && *cp <= '9')
|| (*cp >= 'a' && *cp <= 'z')))
{
- obstack_1grow (&string_obstack, *cp);
+ obstack_1grow (string_obstack, *cp);
cp++;
size++;
}
{
/* Don't set a value if there are more than one
instruction in the string. */
- obstack_blank_fast (&string_obstack, -size);
+ obstack_blank_fast (string_obstack, -size);
size = 0;
cp = sp;
cp++;
}
if (size == 0)
- obstack_1grow (&string_obstack, '*');
+ obstack_1grow (string_obstack, '*');
else
add_mnemonic_string (mnemonic_htab,
- (char *) obstack_next_free (&string_obstack) - size,
+ (char *) obstack_next_free (string_obstack) - size,
size);
i++;
}
/* An insn definition might emit an empty string. */
- if (obstack_object_size (&string_obstack) == 0)
+ if (obstack_object_size (string_obstack) == 0)
return;
- obstack_1grow (&string_obstack, '\0');
+ obstack_1grow (string_obstack, '\0');
set_attr = rtx_alloc (SET_ATTR);
- XSTR (set_attr, 1) = XOBFINISH (&string_obstack, char *);
+ XSTR (set_attr, 1) = XOBFINISH (string_obstack, char *);
attr_name = XNEWVAR (char, strlen (MNEMONIC_ATTR_NAME) + 1);
strcpy (attr_name, MNEMONIC_ATTR_NAME);
XSTR (set_attr, 0) = attr_name;
static int
mnemonic_htab_callback (void **slot, void *info ATTRIBUTE_UNUSED)
{
- obstack_grow (&string_obstack, (char*)*slot, strlen ((char*)*slot));
- obstack_1grow (&string_obstack, ',');
+ struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
+
+ obstack_grow (string_obstack, (char*) *slot, strlen ((char*) *slot));
+ obstack_1grow (string_obstack, ',');
return 1;
}
static void
gen_mnemonic_attr (void)
{
- struct queue_elem *elem;
+ class queue_elem *elem;
rtx mnemonic_attr = NULL;
htab_t mnemonic_htab;
const char *str, *p;
int i;
+ struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
if (have_error)
return;
htab_traverse (mnemonic_htab, mnemonic_htab_callback, NULL);
/* Replace the last ',' with the zero end character. */
- *((char *)obstack_next_free (&string_obstack) - 1) = '\0';
- XSTR (mnemonic_attr, 1) = XOBFINISH (&string_obstack, char *);
+ *((char *) obstack_next_free (string_obstack) - 1) = '\0';
+ XSTR (mnemonic_attr, 1) = XOBFINISH (string_obstack, char *);
}
/* Check if there are DEFINE_ATTRs with the same name. */
static void
check_define_attr_duplicates ()
{
- struct queue_elem *elem;
+ class queue_elem *elem;
htab_t attr_htab;
char * attr_name;
void **slot;
/* The entry point for initializing the reader. */
-bool
-init_rtx_reader_args_cb (int argc, char **argv,
+rtx_reader *
+init_rtx_reader_args_cb (int argc, const char **argv,
bool (*parse_opt) (const char *))
{
/* Prepare to read input. */
split_sequence_num = 1;
peephole2_sequence_num = 1;
- read_md_files (argc, argv, parse_opt, rtx_handle_directive);
+ gen_reader *reader = new gen_reader ();
+ reader->read_md_files (argc, argv, parse_opt);
if (define_attr_queue != NULL)
check_define_attr_duplicates ();
if (define_attr_queue != NULL)
gen_mnemonic_attr ();
- return !have_error;
+ if (have_error)
+ {
+ delete reader;
+ return NULL;
+ }
+
+ return reader;
}
/* Programs that don't have their own options can use this entry point
instead. */
-bool
-init_rtx_reader_args (int argc, char **argv)
+rtx_reader *
+init_rtx_reader_args (int argc, const char **argv)
{
return init_rtx_reader_args_cb (argc, argv, 0);
}
to use elided pattern numbers for anything. */
do
{
- struct queue_elem **queue, *elem;
+ class queue_elem **queue, *elem;
/* Read all patterns from a given queue before moving on to the next. */
if (define_attr_queue != NULL)
&& code != CONCAT
&& code != PARALLEL
&& code != STRICT_LOW_PART
+ && code != ZERO_EXTRACT
&& code != SCRATCH)
pred->allows_non_lvalue = true;
break;
case MATCH_SCRATCH:
+ if (stats->min_scratch_opno == -1)
+ stats->min_scratch_opno = XINT (x, 0);
+ else
+ stats->min_scratch_opno = MIN (stats->min_scratch_opno, XINT (x, 0));
stats->max_scratch_opno = MAX (stats->max_scratch_opno, XINT (x, 0));
break;
stats->max_opno = -1;
stats->max_dup_opno = -1;
+ stats->min_scratch_opno = -1;
stats->max_scratch_opno = -1;
stats->num_dups = 0;