/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987-2015 Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 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 <algorithm>
#undef GENERATOR_FILE
enum true_rtx_doe {
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 'r': case 'w': case '0': case 's':
+ case 'r': case 'p': case 'i': case 'w': case '0': case 's':
break;
default:
return r;
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:
|| 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;
+
+ case VEC_SELECT:
+ if (GET_MODE (pattern) != VOIDmode)
+ {
+ machine_mode mode = GET_MODE (pattern);
+ machine_mode imode = GET_MODE (XEXP (pattern, 0));
+ machine_mode emode
+ = VECTOR_MODE_P (mode) ? GET_MODE_INNER (mode) : mode;
+ if (GET_CODE (XEXP (pattern, 1)) == PARALLEL)
+ {
+ int expected = 1;
+ unsigned int nelems;
+ if (VECTOR_MODE_P (mode)
+ && !GET_MODE_NUNITS (mode).is_constant (&expected))
+ error_at (info->loc,
+ "vec_select with variable-sized mode %s",
+ GET_MODE_NAME (mode));
+ else if (XVECLEN (XEXP (pattern, 1), 0) != expected)
+ error_at (info->loc,
+ "vec_select parallel with %d elements, expected %d",
+ XVECLEN (XEXP (pattern, 1), 0), expected);
+ else if (VECTOR_MODE_P (imode)
+ && GET_MODE_NUNITS (imode).is_constant (&nelems))
+ {
+ int i;
+ for (i = 0; i < expected; ++i)
+ if (CONST_INT_P (XVECEXP (XEXP (pattern, 1), 0, i))
+ && (UINTVAL (XVECEXP (XEXP (pattern, 1), 0, i))
+ >= nelems))
+ error_at (info->loc,
+ "out of bounds selector %u in vec_select, "
+ "expected at most %u",
+ (unsigned)
+ UINTVAL (XVECEXP (XEXP (pattern, 1), 0, i)),
+ nelems - 1);
+ }
+ }
+ if (imode != VOIDmode && !VECTOR_MODE_P (imode))
+ error_at (info->loc, "%smode of first vec_select operand is not a "
+ "vector mode", GET_MODE_NAME (imode));
+ else if (imode != VOIDmode && GET_MODE_INNER (imode) != emode)
+ error_at (info->loc, "element mode mismatch between vec_select "
+ "%smode and its operand %smode",
+ GET_MODE_NAME (emode),
+ GET_MODE_NAME (GET_MODE_INNER (imode)));
+ }
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 'r': case 'w': case '0': case 's':
+ case 'r': case 'p': case 'i': case 'w': case '0': case 's':
break;
default:
to "T *prev, *next;" and a function "void set_parent (list_head <T> *)"
to set the parent list. */
template <typename T>
-struct list_head
+class list_head
{
+public:
/* A range of linked items. */
- struct range
+ class range
{
+ public:
range (T *);
range (T *, T *);
return first == last ? first : 0;
}
\f
-struct state;
+class state;
/* Describes a possible successful return from a routine. */
struct acceptance_type
}
/* Represents a parameter to a pattern routine. */
-struct parameter
+class parameter
{
+public:
/* The C type of parameter. */
enum type_enum {
/* Represents an invalid parameter. */
an ad-hoc enum value on success and -1 on failure. The routine can
be used by any subroutine type. The match can be parameterized by
things like mode, code and UNSPEC number. */
-struct pattern_routine
+class pattern_routine
{
+public:
/* The state that implements the pattern. */
state *s;
static vec <pattern_routine *> patterns;
/* Represents one use of a pattern routine. */
-struct pattern_use
+class pattern_use
{
+public:
/* The pattern routine to use. */
pattern_routine *routine;
};
/* Represents a test performed by a decision. */
-struct rtx_test
+class rtx_test
{
+public:
rtx_test ();
/* The types of test that can be performed. Most of them take as input
/* Check REGNO (X) == LABEL. */
REGNO_FIELD,
+ /* Check known_eq (SUBREG_BYTE (X), LABEL). */
+ SUBREG_FIELD,
+
/* Check XINT (X, u.opno) == LABEL. */
INT_FIELD,
static rtx_test code (position *);
static rtx_test mode (position *);
static rtx_test regno_field (position *);
+ static rtx_test subreg_field (position *);
static rtx_test int_field (position *, int);
static rtx_test wide_int_field (position *, int);
static rtx_test veclen (position *);
return res;
}
+rtx_test
+rtx_test::subreg_field (position *pos)
+{
+ rtx_test res (pos, rtx_test::SUBREG_FIELD);
+ return res;
+}
+
rtx_test
rtx_test::int_field (position *pos, int opno)
{
case rtx_test::CODE:
case rtx_test::MODE:
case rtx_test::REGNO_FIELD:
+ case rtx_test::SUBREG_FIELD:
case rtx_test::VECLEN:
case rtx_test::HAVE_NUM_CLOBBERS:
return true;
/* A simple set of transition labels. Most transitions have a singleton
label, so try to make that case as efficient as possible. */
-struct int_set : public auto_vec <uint64_t, 1>
+class int_set : public auto_vec <uint64_t, 1>
{
+public:
typedef uint64_t *iterator;
int_set ();
iterator end ();
};
-int_set::int_set () {}
+int_set::int_set () : auto_vec<uint64_t, 1> () {}
-int_set::int_set (uint64_t label)
+int_set::int_set (uint64_t label) :
+ auto_vec<uint64_t, 1> ()
{
safe_push (label);
}
-int_set::int_set (const int_set &other)
+int_set::int_set (const int_set &other) :
+ auto_vec<uint64_t, 1> ()
{
safe_splice (other);
}
return !operator == (a, b);
}
-struct decision;
+class decision;
/* Represents a transition between states, dependent on the result of
a test T. */
-struct transition
+class transition
{
+public:
transition (const int_set &, state *, bool);
void set_parent (list_head <transition> *);
to the transition's target state. If no suitable transition exists,
the machine either falls through to the next decision or, if there are no
more decisions to try, fails the match. */
-struct decision : list_head <transition>
+class decision : public list_head <transition>
{
+public:
decision (const rtx_test &);
void set_parent (list_head <decision> *s);
/* Represents one machine state. For each state the machine tries a list
of decisions, in order, and acts on the first match. It fails without
further backtracking if no decisions match. */
-struct state : list_head <decision>
+class state : public list_head <decision>
{
+public:
void set_parent (list_head <state> *) {}
};
const unsigned char TESTED_VECLEN = 2;
/* Represents a set of conditions that are known to hold. */
-struct known_conditions
+class known_conditions
{
+public:
/* A mask of TESTED_ values for each position, indexed by the position's
id field. */
auto_vec <unsigned char> position_tests;
gcc_unreachable ();
case rtx_test::REGNO_FIELD:
+ case rtx_test::SUBREG_FIELD:
case rtx_test::INT_FIELD:
case rtx_test::WIDE_INT_FIELD:
case rtx_test::VECLEN:
return parameter::MODE;
case rtx_test::REGNO_FIELD:
+ case rtx_test::SUBREG_FIELD:
return parameter::UINT;
case rtx_test::INT_FIELD:
}
/* Statistics about a matching routine. */
-struct stats
+class stats
{
+public:
stats ();
/* The total number of decisions in the routine, excluding trivial
st.longest_backtrack, st.longest_backtrack_code);
}
-struct merge_pattern_info;
+class merge_pattern_info;
/* Represents a transition from one pattern to another. */
-struct merge_pattern_transition
+class merge_pattern_transition
{
+public:
merge_pattern_transition (merge_pattern_info *);
/* The target pattern. */
/* Represents a pattern that can might match several states. The pattern
may replace parts of the test with a parameter value. It may also
replace transition labels with parameters. */
-struct merge_pattern_info
+class merge_pattern_info
{
+public:
merge_pattern_info (unsigned int);
/* If PARAM_TEST_P, the state's singleton test should be generalized
/* Describes one way of matching a particular state to a particular
pattern. */
-struct merge_state_result
+class merge_state_result
{
+public:
merge_state_result (merge_pattern_info *, position *, merge_state_result *);
/* A pattern that matches the state. */
/* Information about a state, used while trying to match it against
a pattern. */
-struct merge_state_info
+class merge_state_info
{
+public:
merge_state_info (state *);
/* The state itself. */
/* 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 &);
};
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;
/* Pairs a pattern that needs to be matched with the rtx position at
which the pattern should occur. */
-struct pattern_pos {
+class pattern_pos {
+public:
pattern_pos () {}
pattern_pos (rtx, position *);
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);
}
}
XWINT (pattern, 0), false);
break;
+ case 'p':
+ /* We don't have a way of parsing polynomial offsets yet,
+ and hopefully never will. */
+ s = add_decision (s, rtx_test::subreg_field (pos),
+ SUBREG_BYTE (pattern).to_constant (),
+ false);
+ break;
+
case '0':
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))
+ 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
(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 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 (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);
+ 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, top_pattern, subpos, x);
+ s = match_pattern_2 (s, info, subpos, x);
subpos_ptr = &subpos->next;
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. */
}
/* 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, rtx_test::c_test (c_test), true, false);
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. */
/* Generated automatically by the program `genrecog' from the target\n\
machine description file. */\n\
\n\
+#define IN_TARGET_CODE 1\n\
+\n\
#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\
/* Information used while writing out code. */
-struct output_state
+class output_state
{
+public:
/* The type of routine that we're generating. */
routine_type type;
break;
case parameter::MODE:
- printf ("%smode", GET_MODE_NAME ((machine_mode) param.value));
+ printf ("E_%smode", GET_MODE_NAME ((machine_mode) param.value));
break;
case parameter::INT:
printf (")");
break;
+ case rtx_test::SUBREG_FIELD:
+ printf ("SUBREG_BYTE (");
+ print_test_rtx (os, test);
+ printf (")");
+ break;
+
case rtx_test::WIDE_INT_FIELD:
printf ("XWINT (");
print_test_rtx (os, test);
print_label_value (test, is_param, value);
break;
+ case rtx_test::SUBREG_FIELD:
+ printf ("%s (", invert_p ? "maybe_ne" : "known_eq");
+ print_nonbool_test (os, test);
+ printf (", ");
+ print_label_value (test, is_param, value);
+ printf (")");
+ break;
+
case rtx_test::SAVED_CONST_INT:
gcc_assert (!is_param && value == 1);
print_test_rtx (os, 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 rtx_test::ACCEPT:
static void
print_subroutine (output_state *os, state *s, int proc_id)
{
- /* For now, the top-level "recog" takes a plain "rtx", and performs 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 == 0)
{
printf (" recog_data.insn = NULL;\n");
- if (os->type == RECOG)
- {
- printf (" rtx_insn *insn ATTRIBUTE_UNUSED;\n");
- printf (" insn = safe_as_a <rtx_insn *> (uncast_insn);\n");
- }
}
print_state (os, s, 2, true);
printf ("}\n");
/* Return the rtx pattern for the list of rtxes in a define_peephole2. */
static rtx
-get_peephole2_pattern (rtvec vec)
+get_peephole2_pattern (md_rtx_info *info)
{
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++)
}
XVECLEN (pattern, 0) = j;
if (j == 0)
- error_with_line (pattern_lineno, "empty define_peephole2");
+ error_at (info->loc, "empty define_peephole2");
return pattern;
}
}
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 def = info.def;
acceptance_type acceptance;
acceptance.partial_p = false;
- acceptance.u.full.code = next_insn_code;
+ acceptance.u.full.code = info.index;
rtx pattern;
- switch (GET_CODE (desc))
+ switch (GET_CODE (def))
{
case DEFINE_INSN:
{
/* Match the instruction in the original .md form. */
acceptance.type = RECOG;
acceptance.u.full.u.num_clobbers = 0;
- pattern = add_implicit_parallel (XVEC (desc, 1));
- validate_pattern (pattern, desc, NULL_RTX, 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));
- validate_pattern (pattern, desc, NULL_RTX, 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_insn *gen_split_%d (rtx_insn *, rtx *);\n",
- next_insn_code);
+ info.index);
break;
case DEFINE_PEEPHOLE2:
acceptance.type = PEEPHOLE2;
- pattern = get_peephole2_pattern (XVEC (desc, 0));
- validate_pattern (pattern, desc, NULL_RTX, 0);
- match_pattern (&peephole2_root, pattern, 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_insn *gen_peephole2_%d (rtx_insn *, rtx *);\n",
- next_insn_code);
+ info.index);
break;
default: