/* Generate code from machine description to recognize rtl as insns.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
{
DT_mode, DT_code, DT_veclen,
DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+ DT_const_int,
DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
DT_accept_op, DT_accept_insn
} type;
const RTX_CODE codes[NUM_RTX_CODE];
} preds[] = {
{"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF, SUBREG, REG, MEM, ADDRESSOF}},
+ LABEL_REF, SUBREG, REG, MEM }},
#ifdef PREDICATE_CODES
PREDICATE_CODES
#endif
{"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF, SUBREG, REG, MEM, ADDRESSOF,
+ LABEL_REF, SUBREG, REG, MEM,
PLUS, MINUS, MULT}},
- {"register_operand", {SUBREG, REG, ADDRESSOF}},
- {"pmode_register_operand", {SUBREG, REG, ADDRESSOF}},
+ {"register_operand", {SUBREG, REG}},
+ {"pmode_register_operand", {SUBREG, REG}},
{"scratch_operand", {SCRATCH, REG}},
{"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF}},
{"const_int_operand", {CONST_INT}},
{"const_double_operand", {CONST_INT, CONST_DOUBLE}},
- {"nonimmediate_operand", {SUBREG, REG, MEM, ADDRESSOF}},
+ {"nonimmediate_operand", {SUBREG, REG, MEM}},
{"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
- LABEL_REF, SUBREG, REG, ADDRESSOF}},
+ LABEL_REF, SUBREG, REG}},
{"push_operand", {MEM}},
{"pop_operand", {MEM}},
{"memory_operand", {SUBREG, MEM}},
static struct decision_test *new_decision_test
(enum decision_type, struct decision_test ***);
static rtx find_operand
- (rtx, int);
+ (rtx, int, rtx);
static rtx find_matching_operand
(rtx, int);
static void validate_pattern
static struct decision *
new_decision (const char *position, struct decision_head *last)
{
- struct decision *new
- = (struct decision *) xmalloc (sizeof (struct decision));
+ struct decision *new = xcalloc (1, sizeof (struct decision));
- memset (new, 0, sizeof (*new));
new->success = *last;
new->position = xstrdup (position);
new->number = next_number++;
struct decision_test **place = *pplace;
struct decision_test *test;
- test = (struct decision_test *) xmalloc (sizeof (*test));
+ test = xmalloc (sizeof (*test));
test->next = *place;
test->type = type;
*place = test;
return test;
}
-/* Search for and return operand N. */
+/* Search for and return operand N, stop when reaching node STOP. */
static rtx
-find_operand (rtx pattern, int n)
+find_operand (rtx pattern, int n, rtx stop)
{
const char *fmt;
RTX_CODE code;
int i, j, len;
rtx r;
+ if (pattern == stop)
+ return stop;
+
code = GET_CODE (pattern);
if ((code == MATCH_SCRATCH
- || code == MATCH_INSN
|| code == MATCH_OPERAND
|| code == MATCH_OPERATOR
|| code == MATCH_PARALLEL)
switch (fmt[i])
{
case 'e': case 'u':
- if ((r = find_operand (XEXP (pattern, i), n)) != NULL_RTX)
+ if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX)
return r;
break;
case 'V':
if (! XVEC (pattern, i))
break;
- /* FALLTHRU */
+ /* Fall through. */
case 'E':
for (j = 0; j < XVECLEN (pattern, i); j++)
- if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
+ if ((r = find_operand (XVECEXP (pattern, i, j), n, stop))
+ != NULL_RTX)
return r;
break;
case 'V':
if (! XVEC (pattern, i))
break;
- /* FALLTHRU */
+ /* Fall through. */
case 'E':
for (j = 0; j < XVECLEN (pattern, i); j++)
{
case MATCH_SCRATCH:
return;
-
- case MATCH_INSN:
+ case MATCH_DUP:
+ case MATCH_OP_DUP:
+ case MATCH_PAR_DUP:
+ if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
+ {
+ message_with_line (pattern_lineno,
+ "operand %i duplicated before defined",
+ XINT (pattern, 0));
+ error_count++;
+ }
+ break;
case MATCH_OPERAND:
case MATCH_OPERATOR:
{
&& c != CONST_INT
&& c != CONST_DOUBLE
&& c != CONST
- && c != HIGH
- && c != CONSTANT_P_RTX)
+ && c != HIGH)
allows_non_const = 1;
if (c != REG
&& c != SUBREG
&& c != MEM
- && c != ADDRESSOF
&& c != CONCAT
&& c != PARALLEL
&& c != STRICT_LOW_PART)
if (GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
- /* Find the referant for a DUP. */
+ /* Find the referent for a DUP. */
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));
+ dest = find_operand (insn, 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));
+ src = find_operand (insn, XINT (src, 0), NULL);
dmode = GET_MODE (dest);
smode = GET_MODE (src);
if (depth > max_depth)
max_depth = depth;
- subpos = (char *) xmalloc (depth + 2);
+ subpos = xmalloc (depth + 2);
strcpy (subpos, position);
subpos[depth + 1] = 0;
beyond the end of the vector. */
test = new_decision_test (DT_veclen_ge, &place);
test->u.veclen = XVECLEN (pattern, 2);
- /* FALLTHRU */
+ /* Fall through. */
case MATCH_OPERAND:
case MATCH_SCRATCH:
case MATCH_OPERATOR:
- case MATCH_INSN:
{
const char *pred_name;
RTX_CODE was_code = code;
}
}
+/* Emit a HOST_WIDE_INT as an integer constant expression. We need to take
+ special care to avoid "decimal constant is so large that it is unsigned"
+ warnings in the resulting code. */
+
+static void
+print_host_wide_int (HOST_WIDE_INT val)
+{
+ HOST_WIDE_INT min = (unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1);
+ if (val == min)
+ printf ("(" HOST_WIDE_INT_PRINT_DEC_C "-1)", val + 1);
+ else
+ printf (HOST_WIDE_INT_PRINT_DEC_C, val);
+}
+
/* Emit a switch statement, if possible, for an initial sequence of
nodes at START. Return the first node yet untested. */
case DT_elt_one_int:
case DT_elt_zero_wide:
case DT_elt_zero_wide_safe:
- printf (HOST_WIDE_INT_PRINT_DEC_C, p->tests->u.intval);
+ print_host_wide_int (p->tests->u.intval);
break;
default:
abort ();
case DT_elt_zero_wide:
case DT_elt_zero_wide_safe:
printf ("XWINT (x%d, 0) == ", depth);
- printf (HOST_WIDE_INT_PRINT_DEC_C, p->u.intval);
+ print_host_wide_int (p->u.intval);
+ break;
+
+ case DT_const_int:
+ printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
+ depth, (int) p->u.intval);
break;
case DT_veclen_ge:
break;
case SPLIT:
- printf ("%sreturn gen_split_%d (operands);\n",
+ printf ("%sreturn gen_split_%d (insn, operands);\n",
indent, test->u.insn.code_number);
break;
struct decision_test *test, *last_test;
int uncond;
+ /* Scan the tests and simplify comparisons against small
+ constants. */
+ for (test = p->tests; test; test = test->next)
+ {
+ if (test->type == DT_code
+ && test->u.code == CONST_INT
+ && test->next
+ && test->next->type == DT_elt_zero_wide_safe
+ && -MAX_SAVED_CONST_INT <= test->next->u.intval
+ && test->next->u.intval <= MAX_SAVED_CONST_INT)
+ {
+ test->type = DT_const_int;
+ test->u.intval = test->next->u.intval;
+ test->next = test->next->next;
+ }
+ }
+
last_test = test = p->tests;
uncond = is_unconditional (test, subroutine_type);
if (uncond == 0)
while ((test = test->next) != NULL)
{
- int uncond2;
-
last_test = test;
- uncond2 = is_unconditional (test, subroutine_type);
- if (uncond2 != 0)
+ if (is_unconditional (test, subroutine_type))
break;
printf ("\n && ");
switch (type)
{
case RECOG:
- printf ("%sint recog%s (rtx, rtx, int *);\n", s_or_e, extension);
printf ("%sint\n\
-recog%s (x0, insn, pnum_clobbers)\n\
- rtx x0 ATTRIBUTE_UNUSED;\n\
- rtx insn ATTRIBUTE_UNUSED;\n\
- int *pnum_clobbers ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+recog%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", s_or_e, extension);
break;
case SPLIT:
- printf ("%srtx split%s (rtx, rtx);\n", s_or_e, extension);
printf ("%srtx\n\
-split%s (x0, insn)\n\
- rtx x0 ATTRIBUTE_UNUSED;\n\
- rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
+ s_or_e, extension);
break;
case PEEPHOLE2:
- printf ("%srtx peephole2%s (rtx, rtx, int *);\n",
- s_or_e, extension);
printf ("%srtx\n\
-peephole2%s (x0, insn, _pmatch_len)\n\
- rtx x0 ATTRIBUTE_UNUSED;\n\
- rtx insn ATTRIBUTE_UNUSED;\n\
- int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+peephole2%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *_pmatch_len ATTRIBUTE_UNUSED)\n",
+ s_or_e, extension);
break;
}
{
rtx y = XVECEXP (x, 0, i - 1);
if (GET_CODE (y) != CLOBBER
- || (GET_CODE (XEXP (y, 0)) != REG
+ || (!REG_P (XEXP (y, 0))
&& GET_CODE (XEXP (y, 0)) != MATCH_SCRATCH))
break;
}
case SPLIT:
/* Define the subroutine we will call below and emit in genemit. */
- printf ("extern rtx gen_split_%d (rtx *);\n", next_insn_code);
+ printf ("extern rtx gen_split_%d (rtx, rtx *);\n", next_insn_code);
break;
case PEEPHOLE2:
{
int new_size;
new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
- insn_name_ptr =
- (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
+ insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
memset (insn_name_ptr + insn_name_ptr_size, 0,
sizeof(char *) * (new_size - insn_name_ptr_size));
insn_name_ptr_size = new_size;