/* Generate code from machine description to recognize rtl as insns.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
- This file is part of GNU CC.
+ This file is part of GCC.
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
/* This program is used to produce insn-recog.c, which contains a
struct decision *first;
struct decision *last;
};
-
+
/* A single test. The two accept types aren't tests per-se, but
their equality (or lack thereof) does affect tree merging so
it is convenient to keep them here. */
struct decision_test *next;
/* These types are roughly in the order in which we'd like to test them. */
- enum decision_type {
- DT_mode, DT_code, DT_veclen,
- DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide,
- DT_dup, DT_pred, DT_c_test,
- DT_accept_op, DT_accept_insn
- } type;
+ enum decision_type
+ {
+ DT_mode, DT_code, DT_veclen,
+ DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+ DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
+ DT_accept_op, DT_accept_insn
+ } type;
union
{
of tree nodes. Also, if a predicate can match only one code, we can
hardwire that code into the node testing the predicate. */
-static struct pred_table
+static const struct pred_table
{
- const char *name;
- RTX_CODE codes[NUM_RTX_CODE];
+ const char *const name;
+ const RTX_CODE codes[NUM_RTX_CODE];
} preds[] = {
{"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM}},
#define NUM_KNOWN_PREDS ARRAY_SIZE (preds)
-static const char * special_mode_pred_table[] = {
+static const char *const special_mode_pred_table[] = {
#ifdef SPECIAL_MODE_PREDICATES
SPECIAL_MODE_PREDICATES
#endif
PARAMS ((rtx, enum routine_type));
static void process_tree
PARAMS ((struct decision_head *, enum routine_type));
-
+
static void record_insn_name
PARAMS ((int, const char *));
const char *position;
struct decision_head *last;
{
- register struct decision *new
+ struct decision *new
= (struct decision *) xmalloc (sizeof (struct decision));
memset (new, 0, sizeof (*new));
}
}
- /* A MATCH_OPERAND that is a SET should have an output reload. */
- if (set && code == MATCH_OPERAND
- && XSTR (pattern, 2)[0] != '\0')
+ if (code == MATCH_OPERAND)
{
- if (set_code == '+')
+ const char constraints0 = XSTR (pattern, 2)[0];
+
+ /* In DEFINE_EXPAND, DEFINE_SPLIT, and DEFINE_PEEPHOLE2, we
+ don't use the MATCH_OPERAND constraint, only the predicate.
+ This is confusing to folks doing new ports, so help them
+ not make the mistake. */
+ if (GET_CODE (insn) == DEFINE_EXPAND
+ || GET_CODE (insn) == DEFINE_SPLIT
+ || GET_CODE (insn) == DEFINE_PEEPHOLE2)
{
- if (XSTR (pattern, 2)[0] == '+')
- ;
- /* If we've only got an output reload for this operand,
- we'd better have a matching input operand. */
- else if (XSTR (pattern, 2)[0] == '='
- && find_matching_operand (insn, XINT (pattern, 0)))
- ;
- else
+ if (constraints0)
+ message_with_line (pattern_lineno,
+ "warning: constraints not supported in %s",
+ rtx_name[GET_CODE (insn)]);
+ }
+
+ /* A MATCH_OPERAND that is a SET should have an output reload. */
+ else if (set && constraints0)
+ {
+ if (set_code == '+')
+ {
+ if (constraints0 == '+')
+ ;
+ /* 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)))
+ ;
+ else
+ {
+ message_with_line (pattern_lineno,
+ "operand %d missing in-out reload",
+ XINT (pattern, 0));
+ error_count++;
+ }
+ }
+ else if (constraints0 != '=' && constraints0 != '+')
{
message_with_line (pattern_lineno,
- "operand %d missing in-out reload",
+ "operand %d missing output reload",
XINT (pattern, 0));
error_count++;
}
}
- else if (XSTR (pattern, 2)[0] != '='
- && XSTR (pattern, 2)[0] != '+')
- {
- message_with_line (pattern_lineno,
- "operand %d missing output reload",
- XINT (pattern, 0));
- error_count++;
- }
}
/* Allowing non-lvalues in destinations -- particularly CONST_INT --
/* 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 mistake. Only DEFINE_INSN is eligible, since SPLIT
- and PEEP2 can FAIL within the output pattern. Exclude
+ and PEEP2 can FAIL within the output pattern. Exclude
address_operand, since its mode is related to the mode of
the memory not the operand. Exclude the SET_DEST of a call
instruction, as that is a common idiom. */
dest = SET_DEST (pattern);
src = SET_SRC (pattern);
+ /* STRICT_LOW_PART is a wrapper. Its argument is the real
+ destination, and it's mode should match the source. */
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+
/* Find the referant for a DUP. */
if (GET_CODE (dest) == MATCH_DUP
|| GET_CODE (src) == MATCH_PAR_DUP)
src = find_operand (insn, XINT (src, 0));
- /* STRICT_LOW_PART is a wrapper. Its argument is the real
- destination, and it's mode should match the source. */
- if (GET_CODE (dest) == STRICT_LOW_PART)
- dest = XEXP (dest, 0);
-
dmode = GET_MODE (dest);
smode = GET_MODE (src);
error_count++;
}
- /* If only one of the operands is VOIDmode, and PC or CC0 is
+ /* If only one of the operands is VOIDmode, and PC or CC0 is
not involved, it's probably a mistake. */
else if (dmode != smode
&& GET_CODE (dest) != PC
struct decision_test *test;
struct decision_test **place;
char *subpos;
- register size_t i;
- register const char *fmt;
+ size_t i;
+ const char *fmt;
int depth = strlen (position);
int len;
enum machine_mode mode;
if (depth > max_depth)
max_depth = depth;
- subpos = (char *) alloca (depth + 2);
+ subpos = (char *) xmalloc (depth + 2);
strcpy (subpos, position);
subpos[depth + 1] = 0;
switch (code)
{
case PARALLEL:
- /* Toplevel peephole pattern. */
+ /* Toplevel peephole pattern. */
if (insn_type == PEEPHOLE2 && top)
{
/* We don't need the node we just created -- unlink it. */
for (i = 0; i < (size_t) XVECLEN (pattern, 0); i++)
{
/* Which insn we're looking at is represented by A-Z. We don't
- ever use 'A', however; it is always implied. */
+ ever use 'A', however; it is always implied. */
subpos[depth] = (i > 0 ? 'A' + i : 0);
sub = add_to_sequence (XVECEXP (pattern, 0, i),
last, subpos, insn_type, 0);
last = &sub->success;
}
- return sub;
+ goto ret;
}
/* Else nothing special. */
break;
+ case MATCH_PARALLEL:
+ /* The explicit patterns within a match_parallel enforce a minimum
+ length on the vector. The match_parallel predicate may allow
+ for more elements. We do need to check for this minimum here
+ or the code generated to match the internals may reference data
+ beyond the end of the vector. */
+ test = new_decision_test (DT_veclen_ge, &place);
+ test->u.veclen = XVECLEN (pattern, 2);
+ /* FALLTHRU */
+
case MATCH_OPERAND:
case MATCH_SCRATCH:
case MATCH_OPERATOR:
- case MATCH_PARALLEL:
case MATCH_INSN:
{
const char *pred_name;
test->u.pred.name = pred_name;
test->u.pred.mode = mode;
- /* See if we know about this predicate and save its number. If
- we do, and it only accepts one code, note that fact. The
- predicate `const_int_operand' only tests for a CONST_INT, so
- if we do so we can avoid calling it at all.
+ /* See if we know about this predicate and save its number.
+ If we do, and it only accepts one code, note that fact.
- Finally, if we know that the predicate does not allow
- CONST_INT, we know that the only way the predicate can match
- is if the modes match (here we use the kludge of relying on
- the fact that "address_operand" accepts CONST_INT; otherwise,
- it would have to be a special case), so we can test the mode
- (but we need not). This fact should considerably simplify the
- generated code. */
+ If we know that the predicate does not allow CONST_INT,
+ we know that the only way the predicate can match is if
+ the modes match (here we use the kludge of relying on the
+ fact that "address_operand" accepts CONST_INT; otherwise,
+ it would have to be a special case), so we can test the
+ mode (but we need not). This fact should considerably
+ simplify the generated code. */
for (i = 0; i < NUM_KNOWN_PREDS; i++)
if (! strcmp (preds[i].name, pred_name))
}
else if (fmt[i] == 'w')
{
+ /* If this value actually fits in an int, we can use a switch
+ statement here, so indicate that. */
+ enum decision_type type
+ = ((int) XWINT (pattern, i) == XWINT (pattern, i))
+ ? DT_elt_zero_wide_safe : DT_elt_zero_wide;
+
if (i != 0)
abort ();
- test = new_decision_test (DT_elt_zero_wide, &place);
+ test = new_decision_test (type, &place);
test->u.intval = XWINT (pattern, i);
}
else if (fmt[i] == 'E')
case 'E':
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (pattern, i); j++)
{
subpos[depth] = 'a' + j;
if (this->tests == NULL)
abort ();
+ ret:
+ free (subpos);
return sub;
}
\f
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
return d1->u.intval == d2->u.intval;
default:
}
}
+ /* Tests vs veclen may be known when strict equality is involved. */
+ if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
+ return d1->u.veclen >= d2->u.veclen;
+ if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
+ return d2->u.veclen >= d1->u.veclen;
+
return -1;
}
struct decision_test *t1, *t2;
/* A match_operand with no predicate can match anything. Recognize
- this by the existance of a lone DT_accept_op test. */
+ this by the existence of a lone DT_accept_op test. */
if (d1->type == DT_accept_op || d2->type == DT_accept_op)
return 1;
if (cmp != 0)
{
if (toplevel)
- abort();
+ abort ();
/* If the d2->position was lexically lower, swap. */
if (cmp > 0)
return strcmp (d1->u.c_test, d2->u.c_test) == 0;
case DT_veclen:
+ case DT_veclen_ge:
return d1->u.veclen == d2->u.veclen;
case DT_dup:
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
return d1->u.intval == d2->u.intval;
case DT_accept_op:
}
/* True iff the two nodes are identical (on one level only). Due
- to the way these lists are constructed, we shouldn't have to
+ to the way these lists are constructed, we shouldn't have to
consider different orderings on the tests. */
static int
/* A subroutine of merge_trees; given two nodes that have been declared
identical, cope with two insn accept states. If they differ in the
number of clobbers, then the conflict was created by make_insn_sequence
- and we can drop the with-clobbers version on the floor. If both
+ and we can drop the with-clobbers version on the floor. If both
nodes have no additional clobbers, we have found an ambiguity in the
source machine description. */
that tests just the same mode.
If we have no match, place NEW after the closest match we found. */
-
+
for (old = oldh->last; old; old = old->prev)
{
if (nodes_identical (old, add))
how expensive/important the test is. Given that the tests
are also ordered within the list, examining the first is
sufficient. */
- if (add->tests->type < old->tests->type)
+ if ((int) add->tests->type < (int) old->tests->type)
insert_before = old;
}
}
}
\f
-/* Walk the tree looking for sub-nodes that perform common tests.
+/* Walk the tree looking for sub-nodes that perform common tests.
Factor out the common test into a new node. This enables us
(depending on the test type) to emit switch statements later. */
if (next->tests->type != type)
continue;
- /* Don't want all node types, just those we can turn into
+ /* Don't want all node types, just those we can turn into
switch statements. */
if (type != DT_mode
&& type != DT_code
&& type != DT_veclen
&& type != DT_elt_zero_int
&& type != DT_elt_one_int
- && type != DT_elt_zero_wide)
+ && type != DT_elt_zero_wide_safe)
continue;
/* If we'd been performing more than one test, create a new node
new->tests = first->tests->next;
first->tests->next = NULL;
}
-
+
/* Crop the node tree off after our first test. */
first->next = NULL;
old_last = head->last;
{
struct decision *p, *q, *afterward;
- /* We can't propogate alternatives across subroutine boundaries.
+ /* We can't propagate alternatives across subroutine boundaries.
This is not incorrect, merely a minor optimization loss. */
p = head->first;
if (maybe_both_true (p, q, 1))
break;
- /* If we reached the end of the list without finding one,
+ /* If we reached the end of the list without finding one,
use the incoming afterward position. */
if (!q)
q = afterward;
new state, branch to node AFTERWARD if non-zero, otherwise return.
Failure to move to the new state can only occur if we are trying to
- match multiple insns and we try to step past the end of the stream. */
+ match multiple insns and we try to step past the end of the stream. */
static void
change_state (oldpos, newpos, afterward, indent)
/* Hunt for the last [A-Z] in both strings. */
for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
- if (oldpos[old_has_insn] >= 'A' && oldpos[old_has_insn] <= 'Z')
+ if (ISUPPER (oldpos[old_has_insn]))
break;
for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
- if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
+ if (ISUPPER (newpos[new_has_insn]))
break;
/* Go down to desired level. */
while (depth < ndepth)
{
- /* It's a different insn from the first one. */
- if (newpos[depth] >= 'A' && newpos[depth] <= 'Z')
+ /* It's a different insn from the first one. */
+ if (ISUPPER (newpos[depth]))
{
/* We can only fail if we're moving down the tree. */
if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
{
- printf ("%stem = peep2_next_insn (%d);\n",
+ printf ("%stem = peep2_next_insn (%d);\n",
indent, newpos[depth] - 'A');
}
else
{
- printf ("%stem = peep2_next_insn (%d);\n",
+ printf ("%stem = peep2_next_insn (%d);\n",
indent, newpos[depth] - 'A');
printf ("%sif (tem == NULL_RTX)\n", indent);
if (afterward)
}
printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
}
- else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
+ else if (ISLOWER (newpos[depth]))
printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
indent, depth + 1, depth, newpos[depth] - 'a');
else
print_code (code)
enum rtx_code code;
{
- register const char *p;
+ const char *p;
for (p = GET_RTX_NAME (code); *p; p++)
putchar (TOUPPER (*p));
}
}
}
-/* Emit a switch statement, if possible, for an initial sequence of
+/* Emit a switch statement, if possible, for an initial sequence of
nodes at START. Return the first node yet untested. */
static struct decision *
printf (" switch (GET_CODE (x%d))\n {\n", depth);
code = p->tests->u.code;
- do
+ do
{
if (p != start && p->need_label && needs_label == NULL)
needs_label = p;
|| type == DT_veclen
|| type == DT_elt_zero_int
|| type == DT_elt_one_int
- || type == DT_elt_zero_wide)
+ || type == DT_elt_zero_wide_safe)
{
- printf (" switch (");
+ const char *indent = "";
+
+ /* We cast switch parameter to integer, so we must ensure that the value
+ fits. */
+ if (type == DT_elt_zero_wide_safe)
+ {
+ indent = " ";
+ printf(" if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))\n", depth, depth);
+ }
+ printf ("%s switch (", indent);
switch (type)
{
case DT_mode:
case DT_elt_one_int:
printf ("XINT (x%d, 1)", depth);
break;
- case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
/* Convert result of XWINT to int for portability since some C
compilers won't do it and some will. */
printf ("(int) XWINT (x%d, 0)", depth);
default:
abort ();
}
- printf (")\n {\n");
+ printf (")\n%s {\n", indent);
do
{
if (p != start && p->need_label && needs_label == NULL)
needs_label = p;
- printf (" case ");
+ printf ("%s case ", indent);
switch (type)
{
case DT_mode:
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
printf (HOST_WIDE_INT_PRINT_DEC, p->tests->u.intval);
break;
default:
abort ();
}
- printf (":\n goto L%d;\n", p->success.first->number);
+ printf (":\n%s goto L%d;\n", indent, p->success.first->number);
p->success.first->need_label = 1;
p = p->next;
while (p && p->tests->type == type && !p->tests->next);
case_done:
- printf (" default:\n break;\n }\n");
+ printf ("%s default:\n%s break;\n%s }\n",
+ indent, indent, indent);
return needs_label != NULL ? needs_label : p;
}
break;
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
printf ("XWINT (x%d, 0) == ", depth);
printf (HOST_WIDE_INT_PRINT_DEC, p->u.intval);
break;
+ case DT_veclen_ge:
+ printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
+ break;
+
case DT_dup:
printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);
break;
int match_len = 0, i;
for (i = strlen (p->position) - 1; i >= 0; --i)
- if (p->position[i] >= 'A' && p->position[i] <= 'Z')
+ if (ISUPPER (p->position[i]))
{
match_len = p->position[i] - 'A';
break;
enum routine_type type;
int initial;
{
- register struct decision *p = head->first;
+ struct decision *p = head->first;
putchar ('\n');
if (p->need_label)
const char *s_or_e;
char extension[32];
int i;
-
+
s_or_e = subfunction ? "static " : "";
if (subfunction)
printf ("%sint recog%s PARAMS ((rtx, rtx, int *));\n", s_or_e, extension);
printf ("%sint\n\
recog%s (x0, insn, pnum_clobbers)\n\
- register rtx x0;\n\
+ rtx x0 ATTRIBUTE_UNUSED;\n\
rtx insn ATTRIBUTE_UNUSED;\n\
int *pnum_clobbers ATTRIBUTE_UNUSED;\n", s_or_e, extension);
break;
printf ("%srtx split%s PARAMS ((rtx, rtx));\n", s_or_e, extension);
printf ("%srtx\n\
split%s (x0, insn)\n\
- register rtx x0;\n\
+ rtx x0 ATTRIBUTE_UNUSED;\n\
rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
break;
case PEEPHOLE2:
s_or_e, extension);
printf ("%srtx\n\
peephole2%s (x0, insn, _pmatch_len)\n\
- register rtx x0;\n\
+ rtx x0 ATTRIBUTE_UNUSED;\n\
rtx insn ATTRIBUTE_UNUSED;\n\
int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
break;
}
- printf ("{\n register rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n");
+ printf ("{\n rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n");
for (i = 1; i <= max_depth; i++)
- printf (" register rtx x%d ATTRIBUTE_UNUSED;\n", i);
+ printf (" rtx x%d ATTRIBUTE_UNUSED;\n", i);
printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
#include \"flags.h\"\n\
#include \"hard-reg-set.h\"\n\
#include \"resource.h\"\n\
+#include \"toplev.h\"\n\
+#include \"reload.h\"\n\
\n");
puts ("\n\
memset (&peephole2_tree, 0, sizeof peephole2_tree);
if (argc <= 1)
- fatal ("No input file name.");
+ fatal ("no input file name");
- if (init_md_reader (argv[1]) != SUCCESS_EXIT_CODE)
+ if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
return (FATAL_EXIT_CODE);
next_insn_code = 0;
h = make_insn_sequence (desc, PEEPHOLE2);
merge_trees (&peephole2_tree, &h);
}
-
+
next_index++;
}
new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
insn_name_ptr =
(char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
- memset (insn_name_ptr + insn_name_ptr_size, 0,
+ memset (insn_name_ptr + insn_name_ptr_size, 0,
sizeof(char *) * (new_size - insn_name_ptr_size));
insn_name_ptr_size = new_size;
}
last_real_name = new = xstrdup (name);
last_real_code = code;
}
-
+
insn_name_ptr[code] = new;
-}
+}
\f
static void
debug_decision_2 (test)
fprintf (stderr, "elt0_w=");
fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
break;
+ case DT_elt_zero_wide_safe:
+ fprintf (stderr, "elt0_ws=");
+ fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+ break;
+ case DT_veclen_ge:
+ fprintf (stderr, "veclen>=%d", test->u.veclen);
+ break;
case DT_dup:
fprintf (stderr, "dup=%d", test->u.dup);
break;
fprintf (stderr, "A_op=%d", test->u.opno);
break;
case DT_accept_insn:
- fprintf (stderr, "A_insn=(%d,%d)",
+ fprintf (stderr, "A_insn=(%d,%d)",
test->u.insn.code_number, test->u.insn.num_clobbers_to_add);
break;