/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987-2015 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GCC.
5. Write out C++ code for each function. */
#include "bconfig.h"
+#define INCLUDE_ALGORITHM
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "errors.h"
#include "read-md.h"
#include "gensupport.h"
-#include "hash-table.h"
-#include "inchash.h"
-#include <algorithm>
#undef GENERATOR_FILE
enum true_rtx_doe {
/* The maximum (approximate) depth of block nesting that an individual
routine or subroutine should have. This limit is about keeping the
output readable rather than reducing compile time. */
-static const int MAX_DEPTH = 6;
+static const unsigned int MAX_DEPTH = 6;
/* The minimum number of pseudo-statements that a state must have before
we split it out into a subroutine. */
-static const int MIN_NUM_STATEMENTS = 5;
+static const unsigned int MIN_NUM_STATEMENTS = 5;
/* The number of pseudo-statements a state can have before we consider
splitting out substates into subroutines. This limit is about avoiding
compile-time problems with very big functions (and also about keeping
functions within --param optimization limits, etc.). */
-static const int MAX_NUM_STATEMENTS = 200;
+static const unsigned int MAX_NUM_STATEMENTS = 200;
/* The minimum number of pseudo-statements that can be used in a pattern
routine. */
SUBPATTERN, RECOG, SPLIT, PEEPHOLE2
};
-/* Next number to use as an insn_code. */
-static int next_insn_code;
-
-/* The line number of the start of the pattern currently being processed. */
-static int pattern_lineno;
-
/* The root position (x0). */
static struct position root_pos;
return r;
break;
- case 'i': case 'w': case '0': case 's':
+ case 'i': case 'r': case 'w': case '0': case 's':
break;
default:
return r;
break;
- case 'i': case 'w': case '0': case 's':
+ case 'i': case 'r': case 'w': case '0': case 's':
break;
default:
|| GET_CODE (insn) == DEFINE_PEEPHOLE2);
}
-/* Check for various errors in patterns. SET is nonnull for a destination,
- and is the complete set pattern. SET_CODE is '=' for normal sets, and
- '+' within a context that requires in-out constraints. */
+/* Return the name of the predicate matched by MATCH_RTX. */
+
+static const char *
+predicate_name (rtx match_rtx)
+{
+ if (GET_CODE (match_rtx) == MATCH_SCRATCH)
+ return "scratch_operand";
+ else
+ return XSTR (match_rtx, 1);
+}
+
+/* Return true if OPERAND is a MATCH_OPERAND using a special predicate
+ function. */
+
+static bool
+special_predicate_operand_p (rtx operand)
+{
+ if (GET_CODE (operand) == MATCH_OPERAND)
+ {
+ const char *pred_name = predicate_name (operand);
+ if (pred_name[0] != 0)
+ {
+ const struct pred_data *pred;
+
+ pred = lookup_predicate (pred_name);
+ return pred != NULL && pred->special;
+ }
+ }
+
+ return false;
+}
+
+/* Check for various errors in PATTERN, which is part of INFO.
+ SET is nonnull for a destination, and is the complete set pattern.
+ SET_CODE is '=' for normal sets, and '+' within a context that
+ requires in-out constraints. */
static void
-validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
+validate_pattern (rtx pattern, md_rtx_info *info, rtx set, int set_code)
{
const char *fmt;
RTX_CODE code;
{
const char constraints0 = XSTR (pattern, 1)[0];
- if (!constraints_supported_in_insn_p (insn))
+ if (!constraints_supported_in_insn_p (info->def))
{
if (constraints0)
{
- error_with_line (pattern_lineno,
- "constraints not supported in %s",
- rtx_name[GET_CODE (insn)]);
+ error_at (info->loc, "constraints not supported in %s",
+ GET_RTX_NAME (GET_CODE (info->def)));
}
return;
}
&& constraints0 != '='
&& constraints0 != '+')
{
- error_with_line (pattern_lineno,
- "operand %d missing output reload",
- XINT (pattern, 0));
+ error_at (info->loc, "operand %d missing output reload",
+ XINT (pattern, 0));
}
return;
}
case MATCH_DUP:
case MATCH_OP_DUP:
case MATCH_PAR_DUP:
- if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
- error_with_line (pattern_lineno,
- "operand %i duplicated before defined",
- XINT (pattern, 0));
+ if (find_operand (info->def, XINT (pattern, 0), pattern) == pattern)
+ error_at (info->loc, "operand %i duplicated before defined",
+ XINT (pattern, 0));
break;
case MATCH_OPERAND:
case MATCH_OPERATOR:
const struct pred_data *pred;
const char *c_test;
- if (GET_CODE (insn) == DEFINE_INSN)
- c_test = XSTR (insn, 2);
- else
- c_test = XSTR (insn, 1);
+ c_test = get_c_test (info->def);
if (pred_name[0] != 0)
{
pred = lookup_predicate (pred_name);
if (!pred)
- error_with_line (pattern_lineno, "unknown predicate '%s'",
- pred_name);
+ error_at (info->loc, "unknown predicate '%s'", pred_name);
}
else
pred = 0;
const char *constraints = XSTR (pattern, 2);
const char constraints0 = constraints[0];
- if (!constraints_supported_in_insn_p (insn))
+ if (!constraints_supported_in_insn_p (info->def))
{
if (constraints0)
{
- error_with_line (pattern_lineno,
- "constraints not supported in %s",
- rtx_name[GET_CODE (insn)]);
+ error_at (info->loc, "constraints not supported in %s",
+ GET_RTX_NAME (GET_CODE (info->def)));
}
}
/* If we've only got an output reload for this operand,
we'd better have a matching input operand. */
else if (constraints0 == '='
- && find_matching_operand (insn, XINT (pattern, 0)))
+ && find_matching_operand (info->def,
+ XINT (pattern, 0)))
;
else
- error_with_line (pattern_lineno,
- "operand %d missing in-out reload",
- XINT (pattern, 0));
+ error_at (info->loc, "operand %d missing in-out reload",
+ XINT (pattern, 0));
}
else if (constraints0 != '=' && constraints0 != '+')
- error_with_line (pattern_lineno,
- "operand %d missing output reload",
- XINT (pattern, 0));
+ error_at (info->loc, "operand %d missing output reload",
+ XINT (pattern, 0));
}
/* For matching constraint in MATCH_OPERAND, the digit must be a
sscanf (constraints, "%d", &val);
if (val >= XINT (pattern, 0))
- error_with_line (pattern_lineno,
- "constraint digit %d is not smaller than"
- " operand %d",
- val, XINT (pattern, 0));
+ error_at (info->loc, "constraint digit %d is not"
+ " smaller than operand %d",
+ val, XINT (pattern, 0));
}
while (constraints[0] && constraints[0] != ',')
while not likely to occur at runtime, results in less efficient
code from insn-recog.c. */
if (set && pred && pred->allows_non_lvalue)
- error_with_line (pattern_lineno,
- "destination operand %d allows non-lvalue",
- XINT (pattern, 0));
+ error_at (info->loc, "destination operand %d allows non-lvalue",
+ XINT (pattern, 0));
/* A modeless MATCH_OPERAND can be handy when we can check for
multiple modes in the c_test. In most other cases, it is a
if (GET_MODE (pattern) == VOIDmode
&& code == MATCH_OPERAND
- && GET_CODE (insn) == DEFINE_INSN
+ && GET_CODE (info->def) == DEFINE_INSN
&& pred
&& !pred->special
&& pred->allows_non_const
&& ! (set
&& GET_CODE (set) == SET
&& GET_CODE (SET_SRC (set)) == CALL))
- message_with_line (pattern_lineno,
- "warning: operand %d missing mode?",
- XINT (pattern, 0));
+ message_at (info->loc, "warning: operand %d missing mode?",
+ XINT (pattern, 0));
return;
}
if (GET_CODE (dest) == MATCH_DUP
|| GET_CODE (dest) == MATCH_OP_DUP
|| GET_CODE (dest) == MATCH_PAR_DUP)
- dest = find_operand (insn, XINT (dest, 0), NULL);
+ dest = find_operand (info->def, XINT (dest, 0), NULL);
if (GET_CODE (src) == MATCH_DUP
|| GET_CODE (src) == MATCH_OP_DUP
|| GET_CODE (src) == MATCH_PAR_DUP)
- src = find_operand (insn, XINT (src, 0), NULL);
+ src = find_operand (info->def, XINT (src, 0), NULL);
dmode = GET_MODE (dest);
smode = GET_MODE (src);
- /* The mode of an ADDRESS_OPERAND is the mode of the memory
- reference, not the mode of the address. */
- if (GET_CODE (src) == MATCH_OPERAND
- && ! strcmp (XSTR (src, 1), "address_operand"))
+ /* Mode checking is not performed for special predicates. */
+ if (special_predicate_operand_p (src)
+ || special_predicate_operand_p (dest))
;
/* The operands of a SET must have the same mode unless one
is VOIDmode. */
else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode)
- error_with_line (pattern_lineno,
- "mode mismatch in set: %smode vs %smode",
- GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
+ error_at (info->loc, "mode mismatch in set: %smode vs %smode",
+ GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
/* If only one of the operands is VOIDmode, and PC or CC0 is
not involved, it's probably a mistake. */
{
const char *which;
which = (dmode == VOIDmode ? "destination" : "source");
- message_with_line (pattern_lineno,
- "warning: %s missing a mode?", which);
+ message_at (info->loc, "warning: %s missing a mode?", which);
}
if (dest != SET_DEST (pattern))
- validate_pattern (dest, insn, pattern, '=');
- validate_pattern (SET_DEST (pattern), insn, pattern, '=');
- validate_pattern (SET_SRC (pattern), insn, NULL_RTX, 0);
+ validate_pattern (dest, info, pattern, '=');
+ validate_pattern (SET_DEST (pattern), info, pattern, '=');
+ validate_pattern (SET_SRC (pattern), info, NULL_RTX, 0);
return;
}
case CLOBBER:
- validate_pattern (SET_DEST (pattern), insn, pattern, '=');
+ validate_pattern (SET_DEST (pattern), info, pattern, '=');
return;
case ZERO_EXTRACT:
- validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
- validate_pattern (XEXP (pattern, 1), insn, NULL_RTX, 0);
- validate_pattern (XEXP (pattern, 2), insn, NULL_RTX, 0);
+ validate_pattern (XEXP (pattern, 0), info, set, set ? '+' : 0);
+ validate_pattern (XEXP (pattern, 1), info, NULL_RTX, 0);
+ validate_pattern (XEXP (pattern, 2), info, NULL_RTX, 0);
return;
case STRICT_LOW_PART:
- validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
+ validate_pattern (XEXP (pattern, 0), info, set, set ? '+' : 0);
return;
case LABEL_REF:
- if (GET_MODE (LABEL_REF_LABEL (pattern)) != VOIDmode)
- error_with_line (pattern_lineno,
- "operand to label_ref %smode not VOIDmode",
- GET_MODE_NAME (GET_MODE (LABEL_REF_LABEL (pattern))));
+ if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
+ error_at (info->loc, "operand to label_ref %smode not VOIDmode",
+ GET_MODE_NAME (GET_MODE (XEXP (pattern, 0))));
break;
default:
switch (fmt[i])
{
case 'e': case 'u':
- validate_pattern (XEXP (pattern, i), insn, NULL_RTX, 0);
+ validate_pattern (XEXP (pattern, i), info, NULL_RTX, 0);
break;
case 'E':
for (j = 0; j < XVECLEN (pattern, i); j++)
- validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX, 0);
+ validate_pattern (XVECEXP (pattern, i, j), info, NULL_RTX, 0);
break;
- case 'i': case 'w': case '0': case 's':
+ case 'i': case 'r': case 'w': case '0': case 's':
break;
default:
/* An int parameter. */
INT,
+ /* An unsigned int parameter. */
+ UINT,
+
/* A HOST_WIDE_INT parameter. */
WIDE_INT
};
};
/* Represents a test performed by a decision. */
-struct test
+struct rtx_test
{
- test ();
+ rtx_test ();
/* The types of test that can be performed. Most of them take as input
an rtx X. Some also take as input a transition label LABEL; the others
/* Check GET_MODE (X) == LABEL. */
MODE,
+ /* Check REGNO (X) == LABEL. */
+ REGNO_FIELD,
+
/* Check XINT (X, u.opno) == LABEL. */
INT_FIELD,
acceptance_type acceptance;
} u;
- static test code (position *);
- static test mode (position *);
- static test int_field (position *, int);
- static test wide_int_field (position *, int);
- static test veclen (position *);
- static test peep2_count (int);
- static test veclen_ge (position *, int);
- static test predicate (position *, const pred_data *, machine_mode);
- static test duplicate (position *, int);
- static test pattern (position *, pattern_use *);
- static test have_num_clobbers ();
- static test c_test (const char *);
- static test set_op (position *, int);
- static test accept (const acceptance_type &);
+ static rtx_test code (position *);
+ static rtx_test mode (position *);
+ static rtx_test regno_field (position *);
+ static rtx_test int_field (position *, int);
+ static rtx_test wide_int_field (position *, int);
+ static rtx_test veclen (position *);
+ static rtx_test peep2_count (int);
+ static rtx_test veclen_ge (position *, int);
+ static rtx_test predicate (position *, const pred_data *, machine_mode);
+ static rtx_test duplicate (position *, int);
+ static rtx_test pattern (position *, pattern_use *);
+ static rtx_test have_num_clobbers ();
+ static rtx_test c_test (const char *);
+ static rtx_test set_op (position *, int);
+ static rtx_test accept (const acceptance_type &);
bool terminal_p () const;
bool single_outcome_p () const;
private:
- test (position *, kind_enum);
+ rtx_test (position *, kind_enum);
};
-test::test () {}
+rtx_test::rtx_test () {}
-test::test (position *pos_in, kind_enum kind_in)
+rtx_test::rtx_test (position *pos_in, kind_enum kind_in)
: pos (pos_in), pos_operand (-1), kind (kind_in) {}
-test
-test::code (position *pos)
+rtx_test
+rtx_test::code (position *pos)
+{
+ return rtx_test (pos, rtx_test::CODE);
+}
+
+rtx_test
+rtx_test::mode (position *pos)
{
- return test (pos, test::CODE);
+ return rtx_test (pos, rtx_test::MODE);
}
-test
-test::mode (position *pos)
+rtx_test
+rtx_test::regno_field (position *pos)
{
- return test (pos, test::MODE);
+ rtx_test res (pos, rtx_test::REGNO_FIELD);
+ return res;
}
-test
-test::int_field (position *pos, int opno)
+rtx_test
+rtx_test::int_field (position *pos, int opno)
{
- test res (pos, test::INT_FIELD);
+ rtx_test res (pos, rtx_test::INT_FIELD);
res.u.opno = opno;
return res;
}
-test
-test::wide_int_field (position *pos, int opno)
+rtx_test
+rtx_test::wide_int_field (position *pos, int opno)
{
- test res (pos, test::WIDE_INT_FIELD);
+ rtx_test res (pos, rtx_test::WIDE_INT_FIELD);
res.u.opno = opno;
return res;
}
-test
-test::veclen (position *pos)
+rtx_test
+rtx_test::veclen (position *pos)
{
- return test (pos, test::VECLEN);
+ return rtx_test (pos, rtx_test::VECLEN);
}
-test
-test::peep2_count (int min_len)
+rtx_test
+rtx_test::peep2_count (int min_len)
{
- test res (0, test::PEEP2_COUNT);
+ rtx_test res (0, rtx_test::PEEP2_COUNT);
res.u.min_len = min_len;
return res;
}
-test
-test::veclen_ge (position *pos, int min_len)
+rtx_test
+rtx_test::veclen_ge (position *pos, int min_len)
{
- test res (pos, test::VECLEN_GE);
+ rtx_test res (pos, rtx_test::VECLEN_GE);
res.u.min_len = min_len;
return res;
}
-test
-test::predicate (position *pos, const struct pred_data *data,
- machine_mode mode)
+rtx_test
+rtx_test::predicate (position *pos, const struct pred_data *data,
+ machine_mode mode)
{
- test res (pos, test::PREDICATE);
+ rtx_test res (pos, rtx_test::PREDICATE);
res.u.predicate.data = data;
res.u.predicate.mode_is_param = false;
res.u.predicate.mode = mode;
return res;
}
-test
-test::duplicate (position *pos, int opno)
+rtx_test
+rtx_test::duplicate (position *pos, int opno)
{
- test res (pos, test::DUPLICATE);
+ rtx_test res (pos, rtx_test::DUPLICATE);
res.u.opno = opno;
return res;
}
-test
-test::pattern (position *pos, pattern_use *pattern)
+rtx_test
+rtx_test::pattern (position *pos, pattern_use *pattern)
{
- test res (pos, test::PATTERN);
+ rtx_test res (pos, rtx_test::PATTERN);
res.u.pattern = pattern;
return res;
}
-test
-test::have_num_clobbers ()
+rtx_test
+rtx_test::have_num_clobbers ()
{
- return test (0, test::HAVE_NUM_CLOBBERS);
+ return rtx_test (0, rtx_test::HAVE_NUM_CLOBBERS);
}
-test
-test::c_test (const char *string)
+rtx_test
+rtx_test::c_test (const char *string)
{
- test res (0, test::C_TEST);
+ rtx_test res (0, rtx_test::C_TEST);
res.u.string = string;
return res;
}
-test
-test::set_op (position *pos, int opno)
+rtx_test
+rtx_test::set_op (position *pos, int opno)
{
- test res (pos, test::SET_OP);
+ rtx_test res (pos, rtx_test::SET_OP);
res.u.opno = opno;
return res;
}
-test
-test::accept (const acceptance_type &acceptance)
+rtx_test
+rtx_test::accept (const acceptance_type &acceptance)
{
- test res (0, test::ACCEPT);
+ rtx_test res (0, rtx_test::ACCEPT);
res.u.acceptance = acceptance;
return res;
}
/* Return true if the test represents an unconditionally successful match. */
bool
-test::terminal_p () const
+rtx_test::terminal_p () const
{
- return kind == test::ACCEPT && u.acceptance.type != PEEPHOLE2;
+ return kind == rtx_test::ACCEPT && u.acceptance.type != PEEPHOLE2;
}
/* Return true if the test is a boolean that is always true. */
bool
-test::single_outcome_p () const
+rtx_test::single_outcome_p () const
{
- return terminal_p () || kind == test::SET_OP;
+ return terminal_p () || kind == rtx_test::SET_OP;
}
bool
-operator == (const test &a, const test &b)
+operator == (const rtx_test &a, const rtx_test &b)
{
if (a.pos != b.pos || a.kind != b.kind)
return false;
switch (a.kind)
{
- case test::CODE:
- case test::MODE:
- case test::VECLEN:
- case test::HAVE_NUM_CLOBBERS:
+ case rtx_test::CODE:
+ case rtx_test::MODE:
+ case rtx_test::REGNO_FIELD:
+ case rtx_test::VECLEN:
+ case rtx_test::HAVE_NUM_CLOBBERS:
return true;
- case test::PEEP2_COUNT:
- case test::VECLEN_GE:
+ case rtx_test::PEEP2_COUNT:
+ case rtx_test::VECLEN_GE:
return a.u.min_len == b.u.min_len;
- case test::INT_FIELD:
- case test::WIDE_INT_FIELD:
- case test::DUPLICATE:
- case test::SET_OP:
+ case rtx_test::INT_FIELD:
+ case rtx_test::WIDE_INT_FIELD:
+ case rtx_test::DUPLICATE:
+ case rtx_test::SET_OP:
return a.u.opno == b.u.opno;
- case test::SAVED_CONST_INT:
+ case rtx_test::SAVED_CONST_INT:
return (a.u.integer.is_param == b.u.integer.is_param
&& a.u.integer.value == b.u.integer.value);
- case test::PREDICATE:
+ case rtx_test::PREDICATE:
return (a.u.predicate.data == b.u.predicate.data
&& a.u.predicate.mode_is_param == b.u.predicate.mode_is_param
&& a.u.predicate.mode == b.u.predicate.mode);
- case test::PATTERN:
+ case rtx_test::PATTERN:
return (a.u.pattern->routine == b.u.pattern->routine
&& a.u.pattern->params == b.u.pattern->params);
- case test::C_TEST:
+ case rtx_test::C_TEST:
return strcmp (a.u.string, b.u.string) == 0;
- case test::ACCEPT:
+ case rtx_test::ACCEPT:
return a.u.acceptance == b.u.acceptance;
}
gcc_unreachable ();
}
bool
-operator != (const test &a, const test &b)
+operator != (const rtx_test &a, const rtx_test &b)
{
return !operator == (a, b);
}
transition *prev, *next;
/* The transition should be taken when T has one of these values.
- E.g. for test::CODE this is a set of codes, while for booleans like
- test::PREDICATE it is always a singleton "true". The labels are
+ E.g. for rtx_test::CODE this is a set of codes, while for booleans like
+ rtx_test::PREDICATE it is always a singleton "true". The labels are
sorted in ascending order. */
int_set labels;
bool optional;
/* True if LABELS contains parameter numbers rather than constants.
- E.g. if this is true for a test::CODE, the label is the number
+ E.g. if this is true for a rtx_test::CODE, the label is the number
of an rtx_code parameter rather than an rtx_code itself.
LABELS is always a singleton when this variable is true. */
bool is_param;
more decisions to try, fails the match. */
struct decision : list_head <transition>
{
- decision (const test &);
+ decision (const rtx_test &);
void set_parent (list_head <decision> *s);
bool if_statement_p (uint64_t * = 0) const;
decision *prev, *next;
/* The test to perform. */
- struct test test;
+ rtx_test test;
};
/* Represents one machine state. For each state the machine tries a list
from = static_cast <decision *> (from_in);
}
-decision::decision (const struct test &test_in)
+decision::decision (const rtx_test &test_in)
: prev (0), next (0), test (test_in) {}
/* Set the state to which this decision belongs. */
TRANS. */
static void
-add_decision (state *from, const test &test, transition *trans)
+add_decision (state *from, const rtx_test &test, transition *trans)
{
decision *d = new decision (test);
from->push_back (d);
should be optional. Return the new state. */
static state *
-add_decision (state *from, const test &test, int_set labels, bool optional)
+add_decision (state *from, const rtx_test &test, int_set labels, bool optional)
{
state *to = new state;
add_decision (from, test, new transition (labels, to, optional));
optional. */
static decision *
-insert_decision_before (state::range r, const test &test,
+insert_decision_before (state::range r, const rtx_test &test,
const int_set &labels, bool optional)
{
decision *newd = new decision (test);
uint64_t label;
/* Convert checks for GET_CODE (x) == CONST_INT and XWINT (x, 0) == N
into checks for const_int_rtx[N'], if N is suitably small. */
- if (d->test.kind == test::CODE
+ if (d->test.kind == rtx_test::CODE
&& d->if_statement_p (&label)
&& label == CONST_INT)
if (decision *second = d->first->to->singleton ())
- if (second->test.kind == test::WIDE_INT_FIELD
+ if (d->test.pos == second->test.pos
+ && second->test.kind == rtx_test::WIDE_INT_FIELD
&& second->test.u.opno == 0
&& second->if_statement_p (&label)
&& IN_RANGE (int64_t (label),
-MAX_SAVED_CONST_INT, MAX_SAVED_CONST_INT))
{
- d->test.kind = test::SAVED_CONST_INT;
+ d->test.kind = rtx_test::SAVED_CONST_INT;
d->test.u.integer.is_param = false;
d->test.u.integer.value = label;
d->replace (d->first, second->release ());
paths that reach that code test require the same predicate
to be true. cse_tests will then put the predicate test in
series with the code test. */
- if (d->test.kind == test::CODE)
+ if (d->test.kind == rtx_test::CODE)
if (transition *trans = d->singleton ())
{
state *s = trans->to;
transition *trans2 = d2->singleton ();
if (!trans2)
break;
- if (d2->test.kind == test::PREDICATE)
+ if (d2->test.kind == rtx_test::PREDICATE)
{
d->test = d2->test;
trans->labels = int_set (true);
static bool
common_test_p (decision *d, transition *common, vec <transition *> *where)
{
- if (d->test.kind == test::ACCEPT)
+ if (d->test.kind == rtx_test::ACCEPT)
/* We found a successful return that didn't require COMMON. */
return false;
if (d->test == common->from->test)
as positive proof. */
static bool
-safe_to_hoist_p (decision *d, const test &test, known_conditions *kc)
+safe_to_hoist_p (decision *d, const rtx_test &test, known_conditions *kc)
{
switch (test.kind)
{
- case test::C_TEST:
+ case rtx_test::C_TEST:
/* In general, C tests require everything else to have been
verified and all operands to have been set up. */
return false;
- case test::ACCEPT:
+ case rtx_test::ACCEPT:
/* Don't accept something before all conditions have been tested. */
return false;
- case test::PREDICATE:
+ case rtx_test::PREDICATE:
/* Don't move a predicate over a test for VECLEN_GE, since the
predicate used in a match_parallel can legitimately expect the
length to be checked first. */
subd->test != test;
subd = subd->first->to->first)
if (subd->test.pos == test.pos
- && subd->test.kind == test::VECLEN_GE)
+ && subd->test.kind == rtx_test::VECLEN_GE)
return false;
goto any_rtx;
- case test::DUPLICATE:
+ case rtx_test::DUPLICATE:
/* Don't test for a match_dup until the associated operand has
been set. */
if (!kc->set_operands[test.u.opno])
return false;
goto any_rtx;
- case test::CODE:
- case test::MODE:
- case test::SAVED_CONST_INT:
- case test::SET_OP:
+ case rtx_test::CODE:
+ case rtx_test::MODE:
+ case rtx_test::SAVED_CONST_INT:
+ case rtx_test::SET_OP:
any_rtx:
/* Check whether it is safe to access the rtx under test. */
switch (test.pos->type)
}
gcc_unreachable ();
- case test::INT_FIELD:
- case test::WIDE_INT_FIELD:
- case test::VECLEN:
- case test::VECLEN_GE:
+ case rtx_test::REGNO_FIELD:
+ case rtx_test::INT_FIELD:
+ case rtx_test::WIDE_INT_FIELD:
+ case rtx_test::VECLEN:
+ case rtx_test::VECLEN_GE:
/* These tests access a specific part of an rtx, so are only safe
once we know what the rtx is. */
return kc->position_tests[test.pos->id] & TESTED_CODE;
- case test::PEEP2_COUNT:
- case test::HAVE_NUM_CLOBBERS:
+ case rtx_test::PEEP2_COUNT:
+ case rtx_test::HAVE_NUM_CLOBBERS:
/* These tests can be performed anywhere. */
return true;
- case test::PATTERN:
+ case rtx_test::PATTERN:
gcc_unreachable ();
}
gcc_unreachable ();
/* Make sure that safe_to_hoist_p isn't being overly conservative.
It should realize that D's test is safe in the current
environment. */
- gcc_assert (d->test.kind == test::C_TEST
- || d->test.kind == test::ACCEPT
+ gcc_assert (d->test.kind == rtx_test::C_TEST
+ || d->test.kind == rtx_test::ACCEPT
|| safe_to_hoist_p (d, d->test, kc));
/* D won't be changed any further by the current optimization.
int prev = 0;
switch (d->test.kind)
{
- case test::CODE:
+ case rtx_test::CODE:
prev = kc->position_tests[d->test.pos->id];
kc->position_tests[d->test.pos->id] |= TESTED_CODE;
break;
- case test::VECLEN:
- case test::VECLEN_GE:
+ case rtx_test::VECLEN:
+ case rtx_test::VECLEN_GE:
prev = kc->position_tests[d->test.pos->id];
kc->position_tests[d->test.pos->id] |= TESTED_VECLEN;
break;
- case test::SET_OP:
+ case rtx_test::SET_OP:
prev = kc->set_operands[d->test.u.opno];
gcc_assert (!prev);
kc->set_operands[d->test.u.opno] = true;
break;
- case test::PEEP2_COUNT:
+ case rtx_test::PEEP2_COUNT:
prev = kc->peep2_count;
kc->peep2_count = MAX (prev, d->test.u.min_len);
break;
cse_tests (d->test.pos ? d->test.pos : pos, trans->to, kc);
switch (d->test.kind)
{
- case test::CODE:
- case test::VECLEN:
- case test::VECLEN_GE:
+ case rtx_test::CODE:
+ case rtx_test::VECLEN:
+ case rtx_test::VECLEN_GE:
kc->position_tests[d->test.pos->id] = prev;
break;
- case test::SET_OP:
+ case rtx_test::SET_OP:
kc->set_operands[d->test.u.opno] = prev;
break;
- case test::PEEP2_COUNT:
+ case rtx_test::PEEP2_COUNT:
kc->peep2_count = prev;
break;
or parameter::UNSET if none. */
parameter::type_enum
-transition_parameter_type (test::kind_enum kind)
+transition_parameter_type (rtx_test::kind_enum kind)
{
switch (kind)
{
- case test::CODE:
+ case rtx_test::CODE:
return parameter::CODE;
- case test::MODE:
+ case rtx_test::MODE:
return parameter::MODE;
- case test::INT_FIELD:
- case test::VECLEN:
- case test::PATTERN:
+ case rtx_test::REGNO_FIELD:
+ return parameter::UINT;
+
+ case rtx_test::INT_FIELD:
+ case rtx_test::VECLEN:
+ case rtx_test::PATTERN:
return parameter::INT;
- case test::WIDE_INT_FIELD:
+ case rtx_test::WIDE_INT_FIELD:
return parameter::WIDE_INT;
- case test::PEEP2_COUNT:
- case test::VECLEN_GE:
- case test::SAVED_CONST_INT:
- case test::PREDICATE:
- case test::DUPLICATE:
- case test::HAVE_NUM_CLOBBERS:
- case test::C_TEST:
- case test::SET_OP:
- case test::ACCEPT:
+ case rtx_test::PEEP2_COUNT:
+ case rtx_test::VECLEN_GE:
+ case rtx_test::SAVED_CONST_INT:
+ case rtx_test::PREDICATE:
+ case rtx_test::DUPLICATE:
+ case rtx_test::HAVE_NUM_CLOBBERS:
+ case rtx_test::C_TEST:
+ case rtx_test::SET_OP:
+ case rtx_test::ACCEPT:
return parameter::UNSET;
}
gcc_unreachable ();
int this_operand = (d->test.pos ? operand_pos[d->test.pos->id] : -1);
if (this_operand >= 0)
d->test.pos_operand = this_operand;
- if (d->test.kind == test::SET_OP)
+ if (d->test.kind == rtx_test::SET_OP)
operand_pos[d->test.pos->id] = d->test.u.opno;
for (transition *trans = d->first; trans; trans = trans->next)
find_operand_positions (trans->to, operand_pos);
- if (d->test.kind == test::SET_OP)
+ if (d->test.kind == rtx_test::SET_OP)
operand_pos[d->test.pos->id] = this_operand;
}
}
for_d.num_decisions += 1;
for_d.longest_path += 1;
}
- if (d->test.kind == test::ACCEPT)
+ if (d->test.kind == rtx_test::ACCEPT)
{
for_d.longest_path_code = d->test.u.acceptance.u.full.code;
for_d.longest_backtrack_code = d->test.u.acceptance.u.full.code;
PARAMB alone. */
static bool
-compatible_tests_p (const test &a, const test &b,
+compatible_tests_p (const rtx_test &a, const rtx_test &b,
parameter *parama, parameter *paramb)
{
if (a.kind != b.kind)
return false;
switch (a.kind)
{
- case test::PREDICATE:
+ case rtx_test::PREDICATE:
if (a.u.predicate.data != b.u.predicate.data)
return false;
*parama = parameter (parameter::MODE, false, a.u.predicate.mode);
*paramb = parameter (parameter::MODE, false, b.u.predicate.mode);
return true;
- case test::SAVED_CONST_INT:
+ case rtx_test::SAVED_CONST_INT:
*parama = parameter (parameter::INT, false, a.u.integer.value);
*paramb = parameter (parameter::INT, false, b.u.integer.value);
return true;
/* A hasher of states that treats two states as "equal" if they might be
merged (but trying to be more discriminating than "return true"). */
-struct test_pattern_hasher : typed_noop_remove <merge_state_info>
+struct test_pattern_hasher : nofree_ptr_hash <merge_state_info>
{
- typedef merge_state_info *value_type;
- typedef merge_state_info *compare_type;
static inline hashval_t hash (const value_type &);
static inline bool equal (const value_type &, const compare_type &);
};
parameterizing the first N const_ints of the vector
and then (once we reach the maximum number of parameters)
we go on to match the other elements exactly. */
- if (d1->test.kind == test::WIDE_INT_FIELD)
+ if (d1->test.kind == rtx_test::WIDE_INT_FIELD)
return false;
/* See whether the label has a generalizable type. */
pattern_use *use = new pattern_use;
use->routine = pat->routine;
use->params.splice (params);
- decision *d = new decision (test::pattern (res->root, use));
+ decision *d = new decision (rtx_test::pattern (res->root, use));
/* If the original decision could use an element of operands[] instead
of an rtx variable, try to transfer it to the new decision. */
acceptance.type = SUBPATTERN;
acceptance.partial_p = false;
acceptance.u.full.code = cpi->next_result;
- add_decision (s, test::accept (acceptance), true, false);
+ add_decision (s, rtx_test::accept (acceptance), true, false);
cpi->next_result += 1;
}
const parameter ¶m = params[pat->param_test];
switch (newd->test.kind)
{
- case test::PREDICATE:
+ case rtx_test::PREDICATE:
newd->test.u.predicate.mode_is_param = param.is_param;
newd->test.u.predicate.mode = param.value;
break;
- case test::SAVED_CONST_INT:
+ case rtx_test::SAVED_CONST_INT:
newd->test.u.integer.is_param = param.is_param;
newd->test.u.integer.value = param.value;
break;
break;
}
}
- if (d->test.kind == test::C_TEST)
+ if (d->test.kind == rtx_test::C_TEST)
routine->insn_p = true;
- else if (d->test.kind == test::HAVE_NUM_CLOBBERS)
+ else if (d->test.kind == rtx_test::HAVE_NUM_CLOBBERS)
routine->pnum_clobbers_p = true;
news->push_back (newd);
and so couldn't be shared between states). */
if (decision *d = sinfo->s->singleton ())
/* ACCEPT states are unique, so don't even try to merge them. */
- if (d->test.kind != test::ACCEPT
+ if (d->test.kind != rtx_test::ACCEPT
&& (pattern_have_num_clobbers_p
- || d->test.kind != test::HAVE_NUM_CLOBBERS)
+ || d->test.kind != rtx_test::HAVE_NUM_CLOBBERS)
&& (pattern_c_test_p
- || d->test.kind != test::C_TEST))
+ || d->test.kind != rtx_test::C_TEST))
{
merge_state_info **slot = hashtab.find_slot (sinfo, INSERT);
sinfo->prev_same_test = *slot;
acceptance.partial_p = true;
acceptance.u.subroutine_id = procs.length ();
state *news = new state;
- add_decision (news, test::accept (acceptance), true, false);
+ add_decision (news, rtx_test::accept (acceptance), true, false);
return news;
}
if (!newd->test.single_outcome_p ())
size.num_statements += 1;
trans = newd->singleton ();
- if (newd->test.kind == test::SET_OP
- || newd->test.kind == test::ACCEPT)
+ if (newd->test.kind == rtx_test::SET_OP
+ || newd->test.kind == rtx_test::ACCEPT)
break;
}
/* The target of TRANS is a subroutine candidate. First recurse
if (GET_MODE_CLASS (mode) == MODE_INT
&& (pred->codes[CONST_INT]
|| pred->codes[CONST_DOUBLE]
- || pred->codes[CONST_WIDE_INT]))
+ || pred->codes[CONST_WIDE_INT]
+ || pred->codes[LABEL_REF]))
return false;
return !pred->special && mode != VOIDmode;
return diff < 0;
}
-/* Return the name of the predicate matched by MATCH_RTX. */
-
-static const char *
-predicate_name (rtx match_rtx)
-{
- if (GET_CODE (match_rtx) == MATCH_SCRATCH)
- return "scratch_operand";
- else
- return XSTR (match_rtx, 1);
-}
-
/* Add new decisions to S that check whether the rtx at position POS
matches PATTERN. Return the state that is reached in that case.
TOP_PATTERN is the overall pattern, as passed to match_pattern_1. */
static state *
-match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
+match_pattern_2 (state *s, md_rtx_info *info, position *pos, rtx pattern)
{
auto_vec <pattern_pos, 32> worklist;
auto_vec <pattern_pos, 32> pred_and_mode_tests;
dup_tests.safe_push (pattern_pos (pattern, pos));
/* Use the same code check as the original operand. */
- pattern = find_operand (top_pattern, XINT (pattern, 0), NULL_RTX);
+ pattern = find_operand (info->def, XINT (pattern, 0), NULL_RTX);
/* Fall through. */
case MATCH_PARALLEL:
if (code == GET_CODE (pattern))
{
if (!pred)
- error_with_line (pattern_lineno,
- "unknown predicate '%s'"
- " in '%s' expression",
- pred_name, GET_RTX_NAME (code));
+ error_at (info->loc, "unknown predicate '%s' used in %s",
+ pred_name, GET_RTX_NAME (code));
else if (code == MATCH_PARALLEL
&& pred->singleton != PARALLEL)
- error_with_line (pattern_lineno,
- "predicate '%s' used in match_parallel"
- " does not allow only PARALLEL",
- pred->name);
+ error_at (info->loc, "predicate '%s' used in"
+ " match_parallel does not allow only PARALLEL",
+ pred->name);
}
}
if (code == MATCH_PARALLEL || code == MATCH_PAR_DUP)
{
/* Check that we have a parallel with enough elements. */
- s = add_decision (s, test::code (pos), PARALLEL, false);
+ s = add_decision (s, rtx_test::code (pos), PARALLEL, false);
int min_len = XVECLEN (pattern, 2);
- s = add_decision (s, test::veclen_ge (pos, min_len),
+ s = add_decision (s, rtx_test::veclen_ge (pos, min_len),
true, false);
}
else
bool need_codes = (pred
&& (code == MATCH_OPERATOR
|| code == MATCH_OP_DUP));
- s = add_decision (s, test::code (pos), codes, !need_codes);
+ s = add_decision (s, rtx_test::code (pos), codes, !need_codes);
}
/* Postpone the predicate check until we've checked the rest
default:
{
/* Check that the rtx has the right code. */
- s = add_decision (s, test::code (pos), code, false);
+ s = add_decision (s, rtx_test::code (pos), code, false);
/* Queue a test for the mode if one is specified. */
if (GET_MODE (pattern) != VOIDmode)
/* Make sure the vector has the right number of
elements. */
int length = XVECLEN (pattern, i);
- s = add_decision (s, test::veclen (pos), length, false);
+ s = add_decision (s, rtx_test::veclen (pos),
+ length, false);
position **subpos2_ptr = &pos->xvecexp0s;
for (int j = 0; j < length; j++)
case 'i':
/* Make sure that XINT (X, I) has the right value. */
- s = add_decision (s, test::int_field (pos, i),
+ s = add_decision (s, rtx_test::int_field (pos, i),
XINT (pattern, i), false);
break;
+ case 'r':
+ /* Make sure that REGNO (X) has the right value. */
+ gcc_assert (i == 0);
+ s = add_decision (s, rtx_test::regno_field (pos),
+ REGNO (pattern), false);
+ break;
+
case 'w':
/* Make sure that XWINT (X, I) has the right value. */
- s = add_decision (s, test::wide_int_field (pos, i),
+ s = add_decision (s, rtx_test::wide_int_field (pos, i),
XWINT (pattern, 0), false);
break;
/* Check the mode first, to distinguish things like SImode
and DImode register_operands, as described above. */
machine_mode mode = GET_MODE (e->pattern);
- if (safe_predicate_mode (pred, mode))
- s = add_decision (s, test::mode (e->pos), mode, true);
+ if (pred && safe_predicate_mode (pred, mode))
+ s = add_decision (s, rtx_test::mode (e->pos), mode, true);
/* Assign to operands[] first, so that the rtx usually doesn't
need to be live across the call to the predicate.
since we fully expect to assign to operands[] at some point,
and since the caller usually writes to other parts of
recog_data anyway. */
- s = add_decision (s, test::set_op (e->pos, opno), true, false);
- s = add_decision (s, test::predicate (e->pos, pred, mode),
+ s = add_decision (s, rtx_test::set_op (e->pos, opno),
+ true, false);
+ s = add_decision (s, rtx_test::predicate (e->pos, pred, mode),
true, false);
}
else
/* Historically we've ignored the mode when there's no
predicate. Just set up operands[] unconditionally. */
- s = add_decision (s, test::set_op (e->pos, opno), true, false);
+ s = add_decision (s, rtx_test::set_op (e->pos, opno),
+ true, false);
break;
}
default:
- s = add_decision (s, test::mode (e->pos),
+ s = add_decision (s, rtx_test::mode (e->pos),
GET_MODE (e->pattern), false);
break;
}
/* Finally add rtx_equal_p checks for duplicated operands. */
FOR_EACH_VEC_ELT (dup_tests, i, e)
- s = add_decision (s, test::duplicate (e->pos, XINT (e->pattern, 0)),
+ s = add_decision (s, rtx_test::duplicate (e->pos, XINT (e->pattern, 0)),
true, false);
return s;
}
(1) the rtx doesn't match anything already matched by S
(2) the rtx matches TOP_PATTERN and
- (3) C_TEST is true.
+ (3) the C test required by INFO->def is true
- For peephole2, TOP_PATTERN is the DEFINE_PEEPHOLE2 itself, otherwise
- it is the rtx pattern to match (PARALLEL, SET, etc.). */
+ For peephole2, TOP_PATTERN is a SEQUENCE of the instruction patterns
+ to match, otherwise it is a single instruction pattern. */
static void
-match_pattern_1 (state *s, rtx top_pattern, const char *c_test,
+match_pattern_1 (state *s, md_rtx_info *info, rtx pattern,
acceptance_type acceptance)
{
- if (GET_CODE (top_pattern) == DEFINE_PEEPHOLE2)
+ if (acceptance.type == PEEPHOLE2)
{
/* Match each individual instruction. */
position **subpos_ptr = &peep2_insn_pos_list;
int count = 0;
- for (int i = 0; i < XVECLEN (top_pattern, 0); ++i)
+ for (int i = 0; i < XVECLEN (pattern, 0); ++i)
{
- rtx x = XVECEXP (top_pattern, 0, i);
- /* Ignore scratch register requirements. */
- if (GET_CODE (x) != MATCH_SCRATCH && GET_CODE (x) != MATCH_DUP)
- {
- position *subpos = next_position (subpos_ptr, &root_pos,
- POS_PEEP2_INSN, count);
- if (count > 0)
- s = add_decision (s, test::peep2_count (count + 1),
- true, false);
- s = match_pattern_2 (s, top_pattern, subpos, x);
- subpos_ptr = &subpos->next;
- count += 1;
- }
+ rtx x = XVECEXP (pattern, 0, i);
+ position *subpos = next_position (subpos_ptr, &root_pos,
+ POS_PEEP2_INSN, count);
+ if (count > 0)
+ s = add_decision (s, rtx_test::peep2_count (count + 1),
+ true, false);
+ s = match_pattern_2 (s, info, subpos, x);
+ subpos_ptr = &subpos->next;
+ count += 1;
}
acceptance.u.full.u.match_len = count - 1;
}
else
{
/* Make the rtx itself. */
- s = match_pattern_2 (s, top_pattern, &root_pos, top_pattern);
+ s = match_pattern_2 (s, info, &root_pos, pattern);
/* If the match is only valid when extra clobbers are added,
make sure we're able to pass that information to the caller. */
if (acceptance.type == RECOG && acceptance.u.full.u.num_clobbers)
- s = add_decision (s, test::have_num_clobbers (), true, false);
+ s = add_decision (s, rtx_test::have_num_clobbers (), true, false);
}
/* Make sure that the C test is true. */
+ const char *c_test = get_c_test (info->def);
if (maybe_eval_c_test (c_test) != 1)
- s = add_decision (s, test::c_test (c_test), true, false);
+ s = add_decision (s, rtx_test::c_test (c_test), true, false);
/* Accept the pattern. */
- add_decision (s, test::accept (acceptance), true, false);
+ add_decision (s, rtx_test::accept (acceptance), true, false);
}
/* Like match_pattern_1, but (if merge_states_p) try to merge the
backtracking. */
static void
-match_pattern (state *s, rtx top_pattern, const char *c_test,
+match_pattern (state *s, md_rtx_info *info, rtx pattern,
acceptance_type acceptance)
{
if (merge_states_p)
state root;
/* Add the decisions to a fresh state and then merge the full tree
into the existing one. */
- match_pattern_1 (&root, top_pattern, c_test, acceptance);
+ match_pattern_1 (&root, info, pattern, acceptance);
merge_into_state (s, &root);
}
else
- match_pattern_1 (s, top_pattern, c_test, acceptance);
+ match_pattern_1 (s, info, pattern, acceptance);
}
/* Begin the output file. */
#include \"config.h\"\n\
#include \"system.h\"\n\
#include \"coretypes.h\"\n\
-#include \"tm.h\"\n\
+#include \"backend.h\"\n\
+#include \"predict.h\"\n\
#include \"rtl.h\"\n\
+#include \"memmodel.h\"\n\
#include \"tm_p.h\"\n\
-#include \"hashtab.h\"\n\
-#include \"hash-set.h\"\n\
-#include \"vec.h\"\n\
-#include \"machmode.h\"\n\
-#include \"hard-reg-set.h\"\n\
-#include \"input.h\"\n\
-#include \"function.h\"\n\
+#include \"emit-rtl.h\"\n\
#include \"insn-config.h\"\n\
#include \"recog.h\"\n\
#include \"output.h\"\n\
#include \"flags.h\"\n\
-#include \"hard-reg-set.h\"\n\
-#include \"predict.h\"\n\
-#include \"basic-block.h\"\n\
+#include \"df.h\"\n\
#include \"resource.h\"\n\
#include \"diagnostic-core.h\"\n\
#include \"reload.h\"\n\
#include \"regs.h\"\n\
#include \"tm-constrs.h\"\n\
-#include \"predict.h\"\n\
\n");
puts ("\n\
case parameter::INT:
return "int";
+ case parameter::UINT:
+ return "unsigned int";
+
case parameter::WIDE_INT:
return "HOST_WIDE_INT";
}
case SPLIT:
case PEEPHOLE2:
- return "NULL_RTX";
+ return "NULL";
}
gcc_unreachable ();
}
terminal_pattern_p (decision *d, unsigned int *base_out,
unsigned int *count_out)
{
- if (d->test.kind != test::PATTERN)
+ if (d->test.kind != rtx_test::PATTERN)
return false;
unsigned int base = 0;
unsigned int count = 0;
if (trans->is_param || trans->labels.length () != 1)
return false;
decision *subd = trans->to->singleton ();
- if (!subd || subd->test.kind != test::ACCEPT)
+ if (!subd || subd->test.kind != rtx_test::ACCEPT)
return false;
unsigned int this_base = (subd->test.u.acceptance.u.full.code
- trans->labels[0]);
already available in state OS. */
static bool
-test_position_available_p (output_state *os, const test &test)
+test_position_available_p (output_state *os, const rtx_test &test)
{
return (!test.pos
|| test.pos_operand >= 0
printf ("%d", (int) param.value);
break;
+ case parameter::UINT:
+ printf ("%u", (unsigned int) param.value);
+ break;
+
case parameter::WIDE_INT:
print_host_wide_int (param.value);
break;
/* Print the C expression for the rtx tested by TEST. */
static void
-print_test_rtx (output_state *os, const test &test)
+print_test_rtx (output_state *os, const rtx_test &test)
{
if (test.pos_operand >= 0)
printf ("operands[%d]", test.pos_operand);
/* Print the C expression for non-boolean test TEST. */
static void
-print_nonbool_test (output_state *os, const test &test)
+print_nonbool_test (output_state *os, const rtx_test &test)
{
switch (test.kind)
{
- case test::CODE:
+ case rtx_test::CODE:
printf ("GET_CODE (");
print_test_rtx (os, test);
printf (")");
break;
- case test::MODE:
+ case rtx_test::MODE:
printf ("GET_MODE (");
print_test_rtx (os, test);
printf (")");
break;
- case test::VECLEN:
+ case rtx_test::VECLEN:
printf ("XVECLEN (");
print_test_rtx (os, test);
printf (", 0)");
break;
- case test::INT_FIELD:
+ case rtx_test::INT_FIELD:
printf ("XINT (");
print_test_rtx (os, test);
printf (", %d)", test.u.opno);
break;
- case test::WIDE_INT_FIELD:
+ case rtx_test::REGNO_FIELD:
+ printf ("REGNO (");
+ print_test_rtx (os, test);
+ printf (")");
+ break;
+
+ case rtx_test::WIDE_INT_FIELD:
printf ("XWINT (");
print_test_rtx (os, test);
printf (", %d)", test.u.opno);
break;
- case test::PATTERN:
+ case rtx_test::PATTERN:
{
pattern_routine *routine = test.u.pattern->routine;
printf ("pattern%d (", routine->pattern_id);
break;
}
- case test::PEEP2_COUNT:
- case test::VECLEN_GE:
- case test::SAVED_CONST_INT:
- case test::DUPLICATE:
- case test::PREDICATE:
- case test::SET_OP:
- case test::HAVE_NUM_CLOBBERS:
- case test::C_TEST:
- case test::ACCEPT:
+ case rtx_test::PEEP2_COUNT:
+ case rtx_test::VECLEN_GE:
+ case rtx_test::SAVED_CONST_INT:
+ case rtx_test::DUPLICATE:
+ case rtx_test::PREDICATE:
+ case rtx_test::SET_OP:
+ case rtx_test::HAVE_NUM_CLOBBERS:
+ case rtx_test::C_TEST:
+ case rtx_test::ACCEPT:
gcc_unreachable ();
}
}
decision performs TEST. Print the C code for the label. */
static void
-print_label_value (const test &test, bool is_param, uint64_t value)
+print_label_value (const rtx_test &test, bool is_param, uint64_t value)
{
print_parameter_value (parameter (transition_parameter_type (test.kind),
is_param, value));
Test for inequality if INVERT_P, otherwise test for equality. */
static void
-print_test (output_state *os, const test &test, bool is_param, uint64_t value,
- bool invert_p)
+print_test (output_state *os, const rtx_test &test, bool is_param,
+ uint64_t value, bool invert_p)
{
switch (test.kind)
{
/* Handle the non-boolean TESTs. */
- case test::CODE:
- case test::MODE:
- case test::VECLEN:
- case test::INT_FIELD:
- case test::WIDE_INT_FIELD:
- case test::PATTERN:
+ case rtx_test::CODE:
+ case rtx_test::MODE:
+ case rtx_test::VECLEN:
+ case rtx_test::REGNO_FIELD:
+ case rtx_test::INT_FIELD:
+ case rtx_test::WIDE_INT_FIELD:
+ case rtx_test::PATTERN:
print_nonbool_test (os, test);
printf (" %s ", invert_p ? "!=" : "==");
print_label_value (test, is_param, value);
break;
- case test::SAVED_CONST_INT:
+ case rtx_test::SAVED_CONST_INT:
gcc_assert (!is_param && value == 1);
print_test_rtx (os, test);
printf (" %s const_int_rtx[MAX_SAVED_CONST_INT + ",
printf ("]");
break;
- case test::PEEP2_COUNT:
+ case rtx_test::PEEP2_COUNT:
gcc_assert (!is_param && value == 1);
printf ("peep2_current_count %s %d", invert_p ? "<" : ">=",
test.u.min_len);
break;
- case test::VECLEN_GE:
+ case rtx_test::VECLEN_GE:
gcc_assert (!is_param && value == 1);
printf ("XVECLEN (");
print_test_rtx (os, test);
printf (", 0) %s %d", invert_p ? "<" : ">=", test.u.min_len);
break;
- case test::PREDICATE:
+ case rtx_test::PREDICATE:
gcc_assert (!is_param && value == 1);
printf ("%s%s (", invert_p ? "!" : "", test.u.predicate.data->name);
print_test_rtx (os, test);
printf (")");
break;
- case test::DUPLICATE:
+ case rtx_test::DUPLICATE:
gcc_assert (!is_param && value == 1);
printf ("%srtx_equal_p (", invert_p ? "!" : "");
print_test_rtx (os, test);
printf (", operands[%d])", test.u.opno);
break;
- case test::HAVE_NUM_CLOBBERS:
+ case rtx_test::HAVE_NUM_CLOBBERS:
gcc_assert (!is_param && value == 1);
printf ("pnum_clobbers %s NULL", invert_p ? "==" : "!=");
break;
- case test::C_TEST:
+ case rtx_test::C_TEST:
gcc_assert (!is_param && value == 1);
if (invert_p)
printf ("!");
- print_c_condition (test.u.string);
+ rtx_reader_ptr->print_c_condition (test.u.string);
break;
- case test::ACCEPT:
- case test::SET_OP:
+ case rtx_test::ACCEPT:
+ case rtx_test::SET_OP:
gcc_unreachable ();
}
}
return ES_FALLTHROUGH;
}
}
- else if (d->test.kind == test::ACCEPT)
+ else if (d->test.kind == rtx_test::ACCEPT)
return print_acceptance (d->test.u.acceptance, indent, is_final);
- else if (d->test.kind == test::SET_OP)
+ else if (d->test.kind == rtx_test::SET_OP)
{
printf_indent (indent, "operands[%d] = ", d->test.u.opno);
print_test_rtx (os, d->test);
{
d = trans->to->singleton ();
if (!d
- || d->test.kind == test::ACCEPT
- || d->test.kind == test::SET_OP
+ || d->test.kind == rtx_test::ACCEPT
+ || d->test.kind == rtx_test::SET_OP
|| !d->if_statement_p (&label)
|| !test_position_available_p (os, d->test))
break;
return print_state (os, to, indent, is_final);
}
else if (to->singleton ()
- && to->first->test.kind == test::ACCEPT
+ && to->first->test.kind == rtx_test::ACCEPT
&& single_statement_p (to->first->test.u.acceptance))
{
/* The target of the transition is a simple "return" statement.
if (os->type == SUBPATTERN || os->type == RECOG)
printf (" int res ATTRIBUTE_UNUSED;\n");
else
- printf (" rtx res ATTRIBUTE_UNUSED;\n");
+ printf (" rtx_insn *res ATTRIBUTE_UNUSED;\n");
}
/* Output the definition of pattern routine ROUTINE. */
static void
print_subroutine (output_state *os, state *s, int proc_id)
{
- /* For now, the top-level functions take a plain "rtx", and perform a
- checked cast to "rtx_insn *" for use throughout the rest of the
- function and the code it calls. */
- const char *insn_param
- = proc_id > 0 ? "rtx_insn *insn" : "rtx uncast_insn";
printf ("\n");
switch (os->type)
{
else
printf ("int\nrecog");
printf (" (rtx x1 ATTRIBUTE_UNUSED,\n"
- "\t%s ATTRIBUTE_UNUSED,\n"
- "\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", insn_param);
+ "\trtx_insn *insn ATTRIBUTE_UNUSED,\n"
+ "\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n");
break;
case SPLIT:
if (proc_id)
- printf ("static rtx\nsplit_%d", proc_id);
+ printf ("static rtx_insn *\nsplit_%d", proc_id);
else
- printf ("rtx\nsplit_insns");
- printf (" (rtx x1 ATTRIBUTE_UNUSED, %s ATTRIBUTE_UNUSED)\n",
- insn_param);
+ printf ("rtx_insn *\nsplit_insns");
+ printf (" (rtx x1 ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n");
break;
case PEEPHOLE2:
if (proc_id)
- printf ("static rtx\npeephole2_%d", proc_id);
+ printf ("static rtx_insn *\npeephole2_%d", proc_id);
else
- printf ("rtx\npeephole2_insns");
+ printf ("rtx_insn *\npeephole2_insns");
printf (" (rtx x1 ATTRIBUTE_UNUSED,\n"
- "\t%s ATTRIBUTE_UNUSED,\n"
- "\tint *pmatch_len_ ATTRIBUTE_UNUSED)\n", insn_param);
+ "\trtx_insn *insn ATTRIBUTE_UNUSED,\n"
+ "\tint *pmatch_len_ ATTRIBUTE_UNUSED)\n");
break;
}
print_subroutine_start (os, s, &root_pos);
if (proc_id == 0)
{
- printf (" recog_data.insn = NULL_RTX;\n");
- printf (" rtx_insn *insn ATTRIBUTE_UNUSED;\n");
- printf (" insn = safe_as_a <rtx_insn *> (uncast_insn);\n");
+ printf (" recog_data.insn = NULL;\n");
}
print_state (os, s, 2, true);
printf ("}\n");
print_subroutine (os, root, 0);
}
-/* Return the rtx pattern specified by the list of rtxes in a
- define_insn or define_split. */
+/* Return the rtx pattern for the list of rtxes in a define_peephole2. */
static rtx
-add_implicit_parallel (rtvec vec)
+get_peephole2_pattern (md_rtx_info *info)
{
- if (GET_NUM_ELEM (vec) == 1)
- return RTVEC_ELT (vec, 0);
- else
+ int i, j;
+ rtvec vec = XVEC (info->def, 0);
+ rtx pattern = rtx_alloc (SEQUENCE);
+ XVEC (pattern, 0) = rtvec_alloc (GET_NUM_ELEM (vec));
+ for (i = j = 0; i < GET_NUM_ELEM (vec); i++)
{
- rtx pattern = rtx_alloc (PARALLEL);
- XVEC (pattern, 0) = vec;
- return pattern;
+ rtx x = RTVEC_ELT (vec, i);
+ /* Ignore scratch register requirements. */
+ if (GET_CODE (x) != MATCH_SCRATCH && GET_CODE (x) != MATCH_DUP)
+ {
+ XVECEXP (pattern, 0, j) = x;
+ j++;
+ }
}
+ XVECLEN (pattern, 0) = j;
+ if (j == 0)
+ error_at (info->loc, "empty define_peephole2");
+ return pattern;
}
/* Return true if *PATTERN_PTR is a PARALLEL in which at least one trailing
}
int
-main (int argc, char **argv)
+main (int argc, const char **argv)
{
- rtx desc;
state insn_root, split_root, peephole2_root;
progname = "genrecog";
if (!init_rtx_reader_args (argc, argv))
return (FATAL_EXIT_CODE);
- next_insn_code = 0;
-
write_header ();
/* Read the machine description. */
- while (1)
+ md_rtx_info info;
+ while (read_md_rtx (&info))
{
- desc = read_md_rtx (&pattern_lineno, &next_insn_code);
- if (desc == NULL)
- break;
-
- rtx pattern;
+ rtx def = info.def;
acceptance_type acceptance;
acceptance.partial_p = false;
- acceptance.u.full.code = next_insn_code;
+ acceptance.u.full.code = info.index;
- switch (GET_CODE (desc))
+ rtx pattern;
+ switch (GET_CODE (def))
{
case DEFINE_INSN:
{
/* Match the instruction in the original .md form. */
- pattern = add_implicit_parallel (XVEC (desc, 1));
acceptance.type = RECOG;
acceptance.u.full.u.num_clobbers = 0;
- match_pattern (&insn_root, pattern, XSTR (desc, 2), acceptance);
+ pattern = add_implicit_parallel (XVEC (def, 1));
+ validate_pattern (pattern, &info, NULL_RTX, 0);
+ match_pattern (&insn_root, &info, pattern, acceptance);
/* If the pattern is a PARALLEL with trailing CLOBBERs,
allow recog_for_combine to match without the clobbers. */
if (GET_CODE (pattern) == PARALLEL
&& remove_clobbers (&acceptance, &pattern))
- match_pattern (&insn_root, pattern, XSTR (desc, 2), acceptance);
+ match_pattern (&insn_root, &info, pattern, acceptance);
break;
}
case DEFINE_SPLIT:
acceptance.type = SPLIT;
- pattern = add_implicit_parallel (XVEC (desc, 0));
- match_pattern (&split_root, pattern, XSTR (desc, 1), acceptance);
+ pattern = add_implicit_parallel (XVEC (def, 0));
+ validate_pattern (pattern, &info, NULL_RTX, 0);
+ match_pattern (&split_root, &info, pattern, acceptance);
/* Declare the gen_split routine that we'll call if the
pattern matches. The definition comes from insn-emit.c. */
- printf ("extern rtx gen_split_%d (rtx_insn *, rtx *);\n",
- next_insn_code);
+ printf ("extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n",
+ info.index);
break;
case DEFINE_PEEPHOLE2:
acceptance.type = PEEPHOLE2;
- match_pattern (&peephole2_root, desc, XSTR (desc, 1), acceptance);
+ pattern = get_peephole2_pattern (&info);
+ validate_pattern (pattern, &info, NULL_RTX, 0);
+ match_pattern (&peephole2_root, &info, pattern, acceptance);
/* Declare the gen_peephole2 routine that we'll call if the
pattern matches. The definition comes from insn-emit.c. */
- printf ("extern rtx gen_peephole2_%d (rtx_insn *, rtx *);\n",
- next_insn_code);
+ printf ("extern rtx_insn *gen_peephole2_%d (rtx_insn *, rtx *);\n",
+ info.index);
break;
default: