/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987, 88, 92-95, 97-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "hconfig.h"
#include "system.h"
#include "rtl.h"
-#include "obstack.h"
#include "errors.h"
+#include "gensupport.h"
+
#define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \
printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER))
-static struct obstack obstack;
-struct obstack *rtl_obstack = &obstack;
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
/* Holds an array of names indexed by insn_code_number. */
static char **insn_name_ptr = 0;
static int insn_name_ptr_size = 0;
struct {
int code_number; /* Insn number matched. */
+ int lineno; /* Line number of the insn. */
int num_clobbers_to_add; /* Number of CLOBBERs to be added. */
} insn;
} u;
allocate in each subroutine we make. */
static int max_depth;
+
+/* The line number of the start of the pattern currently being processed. */
+static int pattern_lineno;
+
+/* Count of errors. */
+static int error_count;
\f
/* This table contains a list of the rtl codes that can possibly match a
predicate defined in recog.c. The function `maybe_both_true' uses it to
{"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM, PLUS, MINUS, MULT}},
{"register_operand", {SUBREG, REG}},
+ {"pmode_register_operand", {SUBREG, REG}},
{"scratch_operand", {SCRATCH, REG}},
{"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF}},
{"pop_operand", {MEM}},
{"memory_operand", {SUBREG, MEM}},
{"indirect_operand", {SUBREG, MEM}},
- {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU}},
+ {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
+ UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
+ UNLT, LTGT}},
{"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM}}
};
#define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0])
+static const char * special_mode_pred_table[] = {
+#ifdef SPECIAL_MODE_PREDICATES
+ SPECIAL_MODE_PREDICATES
+#endif
+ "pmode_register_operand"
+};
+
+#define NUM_SPECIAL_MODE_PREDS \
+ (sizeof (special_mode_pred_table) / sizeof (special_mode_pred_table[0]))
+
static struct decision *new_decision
- PROTO((const char *, struct decision_head *));
+ PARAMS ((const char *, struct decision_head *));
static struct decision_test *new_decision_test
- PROTO((enum decision_type, struct decision_test ***));
+ PARAMS ((enum decision_type, struct decision_test ***));
+static rtx find_operand
+ PARAMS ((rtx, int));
+static void validate_pattern
+ PARAMS ((rtx, rtx, rtx));
static struct decision *add_to_sequence
- PROTO((rtx, struct decision_head *, const char *, enum routine_type, int));
+ PARAMS ((rtx, struct decision_head *, const char *, enum routine_type, int));
static int maybe_both_true_2
- PROTO((struct decision_test *, struct decision_test *));
+ PARAMS ((struct decision_test *, struct decision_test *));
static int maybe_both_true_1
- PROTO((struct decision_test *, struct decision_test *));
+ PARAMS ((struct decision_test *, struct decision_test *));
static int maybe_both_true
- PROTO((struct decision *, struct decision *, int));
+ PARAMS ((struct decision *, struct decision *, int));
static int nodes_identical_1
- PROTO((struct decision_test *, struct decision_test *));
+ PARAMS ((struct decision_test *, struct decision_test *));
static int nodes_identical
- PROTO((struct decision *, struct decision *));
+ PARAMS ((struct decision *, struct decision *));
static void merge_accept_insn
- PROTO((struct decision *, struct decision *));
+ PARAMS ((struct decision *, struct decision *));
static void merge_trees
- PROTO((struct decision_head *, struct decision_head *));
+ PARAMS ((struct decision_head *, struct decision_head *));
static void factor_tests
- PROTO((struct decision_head *));
+ PARAMS ((struct decision_head *));
static void simplify_tests
- PROTO((struct decision_head *));
+ PARAMS ((struct decision_head *));
static int break_out_subroutines
- PROTO((struct decision_head *, int));
+ PARAMS ((struct decision_head *, int));
static void find_afterward
- PROTO((struct decision_head *, struct decision *));
+ PARAMS ((struct decision_head *, struct decision *));
static void change_state
- PROTO((const char *, const char *, struct decision *, const char *));
+ PARAMS ((const char *, const char *, struct decision *, const char *));
static void print_code
- PROTO((enum rtx_code));
+ PARAMS ((enum rtx_code));
static void write_afterward
- PROTO((struct decision *, struct decision *, const char *));
+ PARAMS ((struct decision *, struct decision *, const char *));
static struct decision *write_switch
- PROTO((struct decision *, int));
+ PARAMS ((struct decision *, int));
static void write_cond
- PROTO((struct decision_test *, int, enum routine_type));
+ PARAMS ((struct decision_test *, int, enum routine_type));
static void write_action
- PROTO((struct decision_test *, int, int, struct decision *,
- enum routine_type));
+ PARAMS ((struct decision *, struct decision_test *, int, int,
+ struct decision *, enum routine_type));
static int is_unconditional
- PROTO((struct decision_test *, enum routine_type));
+ PARAMS ((struct decision_test *, enum routine_type));
static int write_node
- PROTO((struct decision *, int, enum routine_type));
+ PARAMS ((struct decision *, int, enum routine_type));
static void write_tree_1
- PROTO((struct decision_head *, int, enum routine_type));
+ PARAMS ((struct decision_head *, int, enum routine_type));
static void write_tree
- PROTO((struct decision_head *, const char *, enum routine_type, int));
+ PARAMS ((struct decision_head *, const char *, enum routine_type, int));
static void write_subroutine
- PROTO((struct decision_head *, enum routine_type));
+ PARAMS ((struct decision_head *, enum routine_type));
static void write_subroutines
- PROTO((struct decision_head *, enum routine_type));
+ PARAMS ((struct decision_head *, enum routine_type));
static void write_header
- PROTO((void));
+ PARAMS ((void));
static struct decision_head make_insn_sequence
- PROTO((rtx, enum routine_type));
+ PARAMS ((rtx, enum routine_type));
static void process_tree
- PROTO((struct decision_head *, enum routine_type));
+ PARAMS ((struct decision_head *, enum routine_type));
static void record_insn_name
- PROTO((int, const char *));
+ PARAMS ((int, const char *));
+static void debug_decision_0
+ PARAMS ((struct decision *, int, int));
static void debug_decision_1
- PROTO((struct decision *, int));
+ PARAMS ((struct decision *, int));
static void debug_decision_2
- PROTO((struct decision_test *));
+ PARAMS ((struct decision_test *));
extern void debug_decision
- PROTO((struct decision *));
+ PARAMS ((struct decision *));
+extern void debug_decision_list
+ PARAMS ((struct decision *));
\f
/* Create a new node in sequence after LAST. */
return test;
}
+/* Search for and return operand N. */
+
+static rtx
+find_operand (pattern, n)
+ rtx pattern;
+ int n;
+{
+ const char *fmt;
+ RTX_CODE code;
+ int i, j, len;
+ rtx r;
+
+ code = GET_CODE (pattern);
+ if ((code == MATCH_SCRATCH
+ || code == MATCH_INSN
+ || code == MATCH_OPERAND
+ || code == MATCH_OPERATOR
+ || code == MATCH_PARALLEL)
+ && XINT (pattern, 0) == n)
+ return pattern;
+
+ fmt = GET_RTX_FORMAT (code);
+ len = GET_RTX_LENGTH (code);
+ for (i = 0; i < len; i++)
+ {
+ switch (fmt[i])
+ {
+ case 'e': case 'u':
+ if ((r = find_operand (XEXP (pattern, i), n)) != NULL_RTX)
+ return r;
+ break;
+
+ case 'E':
+ for (j = 0; j < XVECLEN (pattern, i); j++)
+ if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
+ return r;
+ break;
+
+ case 'i': case 'w': case '0': case 's':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ return NULL;
+}
+
+/* Check for various errors in patterns. SET is nonnull for a destination,
+ and is the complete set pattern. */
+
+static void
+validate_pattern (pattern, insn, set)
+ rtx pattern;
+ rtx insn;
+ rtx set;
+{
+ const char *fmt;
+ RTX_CODE code;
+ size_t i, len;
+ int j;
+
+ code = GET_CODE (pattern);
+ switch (code)
+ {
+ case MATCH_SCRATCH:
+ return;
+
+ case MATCH_INSN:
+ case MATCH_OPERAND:
+ case MATCH_OPERATOR:
+ {
+ const char *pred_name = XSTR (pattern, 1);
+ int allows_non_lvalue = 1, allows_non_const = 1;
+ int special_mode_pred = 0;
+ const char *c_test;
+
+ if (GET_CODE (insn) == DEFINE_INSN)
+ c_test = XSTR (insn, 2);
+ else
+ c_test = XSTR (insn, 1);
+
+ if (pred_name[0] != 0)
+ {
+ for (i = 0; i < NUM_KNOWN_PREDS; i++)
+ if (! strcmp (preds[i].name, pred_name))
+ break;
+
+ if (i < NUM_KNOWN_PREDS)
+ {
+ int j;
+
+ allows_non_lvalue = allows_non_const = 0;
+ for (j = 0; preds[i].codes[j] != 0; j++)
+ {
+ RTX_CODE c = preds[i].codes[j];
+ if (c != LABEL_REF
+ && c != SYMBOL_REF
+ && c != CONST_INT
+ && c != CONST_DOUBLE
+ && c != CONST
+ && c != HIGH
+ && c != CONSTANT_P_RTX)
+ allows_non_const = 1;
+
+ if (c != REG
+ && c != SUBREG
+ && c != MEM
+ && c != CONCAT
+ && c != PARALLEL
+ && c != STRICT_LOW_PART)
+ allows_non_lvalue = 1;
+ }
+ }
+ else
+ {
+#ifdef PREDICATE_CODES
+ /* If the port has a list of the predicates it uses but
+ omits one, warn. */
+ message_with_line (pattern_lineno,
+ "warning: `%s' not in PREDICATE_CODES",
+ pred_name);
+#endif
+ }
+
+ for (i = 0; i < NUM_SPECIAL_MODE_PREDS; ++i)
+ if (strcmp (pred_name, special_mode_pred_table[i]) == 0)
+ {
+ special_mode_pred = 1;
+ break;
+ }
+ }
+
+ /* A MATCH_OPERAND that is a SET should have an output reload. */
+ if (set
+ && code == MATCH_OPERAND
+ && XSTR (pattern, 2)[0] != '\0'
+ && 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 --
+ while not likely to occur at runtime, results in less efficient
+ code from insn-recog.c. */
+ if (set
+ && pred_name[0] != '\0'
+ && allows_non_lvalue)
+ {
+ message_with_line (pattern_lineno,
+ "warning: 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 mistake. Only DEFINE_INSN is eligible, since SPLIT
+ 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. */
+
+ if (GET_MODE (pattern) == VOIDmode
+ && code == MATCH_OPERAND
+ && GET_CODE (insn) == DEFINE_INSN
+ && allows_non_const
+ && ! special_mode_pred
+ && pred_name[0] != '\0'
+ && strcmp (pred_name, "address_operand") != 0
+ && strstr (c_test, "operands") == NULL
+ && ! (set
+ && GET_CODE (set) == SET
+ && GET_CODE (SET_SRC (set)) == CALL))
+ {
+ message_with_line (pattern_lineno,
+ "warning: operand %d missing mode?",
+ XINT (pattern, 0));
+ }
+ return;
+ }
+
+ case SET:
+ {
+ enum machine_mode dmode, smode;
+ rtx dest, src;
+
+ dest = SET_DEST (pattern);
+ src = SET_SRC (pattern);
+
+ /* Find the referant 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));
+
+ 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));
+
+ /* 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);
+
+ /* 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"))
+ ;
+
+ /* The operands of a SET must have the same mode unless one
+ is VOIDmode. */
+ else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode)
+ {
+ message_with_line (pattern_lineno,
+ "mode mismatch in set: %smode vs %smode",
+ GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
+ error_count++;
+ }
+
+ /* 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
+ && GET_CODE (dest) != CC0
+ && GET_CODE (src) != PC
+ && GET_CODE (src) != CC0
+ && GET_CODE (src) != CONST_INT)
+ {
+ const char *which;
+ which = (dmode == VOIDmode ? "destination" : "source");
+ message_with_line (pattern_lineno,
+ "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);
+ return;
+ }
+
+ case CLOBBER:
+ validate_pattern (SET_DEST (pattern), insn, pattern);
+ return;
+
+ case LABEL_REF:
+ if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
+ {
+ message_with_line (pattern_lineno,
+ "operand to label_ref %smode not VOIDmode",
+ GET_MODE_NAME (GET_MODE (XEXP (pattern, 0))));
+ error_count++;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ len = GET_RTX_LENGTH (code);
+ for (i = 0; i < len; i++)
+ {
+ switch (fmt[i])
+ {
+ case 'e': case 'u':
+ validate_pattern (XEXP (pattern, i), insn, NULL_RTX);
+ break;
+
+ case 'E':
+ for (j = 0; j < XVECLEN (pattern, i); j++)
+ validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX);
+ break;
+
+ case 'i': case 'w': case '0': case 's':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
+
/* Create a chain of nodes to verify that an rtl expression matches
PATTERN.
if (i < NUM_KNOWN_PREDS)
{
- int allows_const_int, j;
+ int j;
test->u.pred.index = i;
}
}
else
- {
- test->u.pred.index = -1;
-#ifdef PREDICATE_CODES
- /* If the port has a list of the predicates it uses but
- omits one, warn. */
- fprintf (stderr, "Warning: `%s' not in PREDICATE_CODES\n",
- pred_name);
-#endif
- }
+ test->u.pred.index = -1;
}
/* Can't enforce a mode if we allow const_int. */
pattern = XEXP (pattern, 0);
goto restart;
- case SET:
- /* The operands of a SET must have the same mode unless one
- is VOIDmode. */
- if (GET_MODE (SET_SRC (pattern)) != VOIDmode
- && GET_MODE (SET_DEST (pattern)) != VOIDmode
- && GET_MODE (SET_SRC (pattern)) != GET_MODE (SET_DEST (pattern))
- /* The mode of an ADDRESS_OPERAND is the mode of the memory
- reference, not the mode of the address. */
- && ! (GET_CODE (SET_SRC (pattern)) == MATCH_OPERAND
- && ! strcmp (XSTR (SET_SRC (pattern), 1), "address_operand")))
- {
- print_rtl (stderr, pattern);
- fputc ('\n', stderr);
- fatal ("mode mismatch in SET");
- }
- break;
-
- case LABEL_REF:
- if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
- {
- print_rtl (stderr, pattern);
- fputc ('\n', stderr);
- fatal ("operand to LABEL_REF not VOIDmode");
- }
- break;
-
default:
break;
}
{
if (d2->type == DT_mode)
{
- if (d1->u.pred.mode != d2->u.mode)
- return 0;
- }
- else if (d2->type == DT_pred)
- {
- if (d2->u.pred.mode != VOIDmode
- && d1->u.pred.mode != d2->u.pred.mode)
+ if (d1->u.pred.mode != d2->u.mode
+ /* The mode of an address_operand predicate is the
+ mode of the memory, not the operand. It can only
+ be used for testing the predicate, so we must
+ ignore it here. */
+ && strcmp (d1->u.pred.name, "address_operand") != 0)
return 0;
}
+ /* Don't check two predicate modes here, because if both predicates
+ accept CONST_INT, then both can still be true even if the modes
+ are different. If they don't accept CONST_INT, there will be a
+ separate DT_mode that will make maybe_both_true_1 return 0. */
}
if (d1->u.pred.index >= 0)
}
/* For success, they should now both be null. */
- return t1 == t2;
+ if (t1 != t2)
+ return 0;
+
+ /* Check that their subnodes are at the same position, as any one set
+ of sibling decisions must be at the same position. */
+ if (d1->success.first
+ && d2->success.first
+ && strcmp (d1->success.first->position, d2->success.first->position))
+ return 0;
+
+ return 1;
}
/* A subroutine of merge_trees; given two nodes that have been declared
}
else
{
- fatal ("Two actions at one point in tree for insns \"%s\" (%d) and \"%s\" (%d)",
- get_insn_name (old->u.insn.code_number),
- old->u.insn.code_number,
- get_insn_name (add->u.insn.code_number),
- add->u.insn.code_number);
+ message_with_line (add->u.insn.lineno, "`%s' matches `%s'",
+ get_insn_name (add->u.insn.code_number),
+ get_insn_name (old->u.insn.code_number));
+ message_with_line (old->u.insn.lineno, "previous definition of `%s'",
+ get_insn_name (old->u.insn.code_number));
+ error_count++;
}
}
for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
if (oldpos[old_has_insn] >= 'A' && oldpos[old_has_insn] <= 'Z')
break;
- for (new_has_insn = odepth - 1; new_has_insn >= 0; --new_has_insn)
+ for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
break;
- /* Make sure to reset the _last_insn pointer when popping back up. */
- if (old_has_insn >= 0 && new_has_insn < 0)
- printf ("%s_last_insn = insn;\n", indent);
-
/* Go down to desired level. */
while (depth < ndepth)
{
/* We can only fail if we're moving down the tree. */
if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
{
- printf ("%s_last_insn = recog_next_insn (insn, %d);\n",
+ printf ("%stem = peep2_next_insn (%d);\n",
indent, newpos[depth] - 'A');
}
else
{
- printf ("%stem = recog_next_insn (insn, %d);\n",
+ printf ("%stem = peep2_next_insn (%d);\n",
indent, newpos[depth] - 'A');
printf ("%sif (tem == NULL_RTX)\n", indent);
if (afterward)
printf ("%s goto L%d;\n", indent, afterward->number);
else
printf ("%s goto ret0;\n", indent);
- printf ("%s_last_insn = tem;\n", indent);
}
- printf ("%sx%d = PATTERN (_last_insn);\n", indent, depth + 1);
+ printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
}
else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
{
char codemap[NUM_RTX_CODE];
struct decision *ret;
+ RTX_CODE code;
memset (codemap, 0, sizeof(codemap));
printf (" switch (GET_CODE (x%d))\n {\n", depth);
+ code = p->tests->u.code;
do
{
- RTX_CODE code = p->tests->u.code;
printf (" case ");
print_code (code);
printf (":\n goto L%d;\n", p->success.first->number);
codemap[code] = 1;
p = p->next;
}
- while (p && p->tests->type == DT_code && !p->tests->next);
+ while (p
+ && ! p->tests->next
+ && p->tests->type == DT_code
+ && ! codemap[code = p->tests->u.code]);
/* If P is testing a predicate that we know about and we haven't
seen any of the codes that are valid for the predicate, we can
|| type == DT_elt_one_int
|| type == DT_elt_zero_wide)
{
- const char *str;
-
printf (" switch (");
switch (type)
{
case DT_mode:
- str = "GET_MODE (x%d)";
+ printf ("GET_MODE (x%d)", depth);
break;
case DT_veclen:
- str = "XVECLEN (x%d, 0)";
+ printf ("XVECLEN (x%d, 0)", depth);
break;
case DT_elt_zero_int:
- str = "XINT (x%d, 0)";
+ printf ("XINT (x%d, 0)", depth);
break;
case DT_elt_one_int:
- str = "XINT (x%d, 1)";
+ printf ("XINT (x%d, 1)", depth);
break;
case DT_elt_zero_wide:
- str = "XWINT (x%d, 0)";
+ /* 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);
break;
default:
abort ();
}
- printf (str, depth);
printf (")\n {\n");
do
perform a state change. For the `accept' tests we must do more work. */
static void
-write_action (test, depth, uncond, success, subroutine_type)
+write_action (p, test, depth, uncond, success, subroutine_type)
+ struct decision *p;
struct decision_test *test;
int depth, uncond;
struct decision *success;
break;
case PEEPHOLE2:
- printf ("%stem = gen_peephole2_%d (insn, operands);\n",
- indent, test->u.insn.code_number);
- printf ("%sif (tem != 0)\n%s goto ret1;\n", indent, indent);
+ {
+ int match_len = 0, i;
+
+ for (i = strlen (p->position) - 1; i >= 0; --i)
+ if (p->position[i] >= 'A' && p->position[i] <= 'Z')
+ {
+ match_len = p->position[i] - 'A';
+ break;
+ }
+ printf ("%s*_pmatch_len = %d;\n", indent, match_len);
+ printf ("%stem = gen_peephole2_%d (insn, operands);\n",
+ indent, test->u.insn.code_number);
+ printf ("%sif (tem != 0)\n%s return tem;\n", indent, indent);
+ }
break;
default:
printf (")\n");
}
- write_action (last_test, depth, uncond, p->success.first, subroutine_type);
+ write_action (p, last_test, depth, uncond, p->success.first, subroutine_type);
return uncond > 0;
}
};
static const char * const call_suffix[] = {
- ", pnum_clobbers", "", ", _plast_insn"
+ ", pnum_clobbers", "", ", _pmatch_len"
};
/* This node has been broken out into a separate subroutine.
struct decision_head *head;
enum routine_type type;
{
- static const char * const proto_pattern[] = {
- "%sint recog%s PROTO ((rtx, rtx, int *));\n",
- "%srtx split%s PROTO ((rtx, rtx));\n",
- "%srtx peephole2%s PROTO ((rtx, rtx, rtx *));\n"
- };
-
- static const char * const decl_pattern[] = {
-"%sint\n\
-recog%s (x0, insn, pnum_clobbers)\n\
- register rtx x0;\n\
- rtx insn ATTRIBUTE_UNUSED;\n\
- int *pnum_clobbers ATTRIBUTE_UNUSED;\n",
-
-"%srtx\n\
-split%s (x0, insn)\n\
- register rtx x0;\n\
- rtx insn ATTRIBUTE_UNUSED;\n",
-
-"%srtx\n\
-peephole2%s (x0, insn, _plast_insn)\n\
- register rtx x0;\n\
- rtx insn ATTRIBUTE_UNUSED;\n\
- rtx *_plast_insn ATTRIBUTE_UNUSED;\n"
- };
-
- int subfunction = head->first->subroutine_number;
+ int subfunction = head->first ? head->first->subroutine_number : 0;
const char *s_or_e;
char extension[32];
int i;
else
strcpy (extension, "_insns");
- printf (proto_pattern[type], s_or_e, extension);
- printf (decl_pattern[type], s_or_e, extension);
+ switch (type)
+ {
+ case RECOG:
+ 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 insn ATTRIBUTE_UNUSED;\n\
+ int *pnum_clobbers ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+ break;
+ case SPLIT:
+ 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 insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+ break;
+ case PEEPHOLE2:
+ printf ("%srtx peephole2%s PARAMS ((rtx, rtx, int *));\n",
+ s_or_e, extension);
+ printf ("%srtx\n\
+peephole2%s (x0, insn, _pmatch_len)\n\
+ register rtx x0;\n\
+ rtx insn ATTRIBUTE_UNUSED;\n\
+ int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+ break;
+ }
- printf ("{\n register rtx * const operands = &recog_data.operand[0];\n");
+ printf ("{\n register 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);
- if (type == PEEPHOLE2)
- printf (" register rtx _last_insn = insn;\n");
printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
- write_tree (head, "", type, 1);
+ if (head->first)
+ write_tree (head, "", type, 1);
+ else
+ printf (" goto ret0;\n");
- if (type == PEEPHOLE2)
- printf (" ret1:\n *_plast_insn = _last_insn;\n return tem;\n");
printf (" ret0:\n return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
}
struct decision *last;
struct decision_test *test, **place;
struct decision_head head;
+ char c_test_pos[2];
record_insn_name (next_insn_code, (type == RECOG ? XSTR (insn, 0) : NULL));
+ c_test_pos[0] = '\0';
if (type == PEEPHOLE2)
{
int i, j;
}
}
XVECLEN (x, 0) = j;
+
+ c_test_pos[0] = 'A' + j - 1;
+ c_test_pos[1] = '\0';
}
else if (XVECLEN (insn, type == RECOG) == 1)
x = XVECEXP (insn, type == RECOG, 0);
PUT_MODE (x, VOIDmode);
}
+ validate_pattern (x, insn, NULL_RTX);
+
memset(&head, 0, sizeof(head));
last = add_to_sequence (x, &head, "", type, 1);
/* Need a new node if we have another test to add. */
if (test->type == DT_accept_op)
{
- last = new_decision ("", &last->success);
+ last = new_decision (c_test_pos, &last->success);
place = &last->tests;
}
test = new_decision_test (DT_c_test, &place);
test = new_decision_test (DT_accept_insn, &place);
test->u.insn.code_number = next_insn_code;
+ test->u.insn.lineno = pattern_lineno;
test->u.insn.num_clobbers_to_add = 0;
switch (type)
test = new_decision_test (DT_accept_insn, &place);
test->u.insn.code_number = next_insn_code;
+ test->u.insn.lineno = pattern_lineno;
test->u.insn.num_clobbers_to_add = XVECLEN (x, 0) - i;
merge_trees (&head, &clobber_head);
case SPLIT:
/* Define the subroutine we will call below and emit in genemit. */
- printf ("extern rtx gen_split_%d PROTO ((rtx *));\n", next_insn_code);
+ printf ("extern rtx gen_split_%d PARAMS ((rtx *));\n", next_insn_code);
break;
case PEEPHOLE2:
/* Define the subroutine we will call below and emit in genemit. */
- printf ("extern rtx gen_peephole2_%d PROTO ((rtx, rtx *));\n",
+ printf ("extern rtx gen_peephole2_%d PARAMS ((rtx, rtx *));\n",
next_insn_code);
break;
}
- next_insn_code++;
return head;
}
enum routine_type subroutine_type;
{
if (head->first == NULL)
- return;
+ {
+ /* We can elide peephole2_insns, but not recog or split_insns. */
+ if (subroutine_type == PEEPHOLE2)
+ return;
+ }
+ else
+ {
+ factor_tests (head);
- factor_tests (head);
- simplify_tests (head);
+ next_subroutine_number = 0;
+ break_out_subroutines (head, 1);
+ find_afterward (head, NULL);
- next_subroutine_number = 0;
- break_out_subroutines (head, 1);
- find_afterward (head, NULL);
+ /* We run this after find_afterward, because find_afterward needs
+ the redundant DT_mode tests on predicates to determine whether
+ two tests can both be true or not. */
+ simplify_tests(head);
+
+ write_subroutines (head, subroutine_type);
+ }
- write_subroutines (head, subroutine_type);
write_subroutine (head, subroutine_type);
}
\f
+extern int main PARAMS ((int, char **));
+
int
main (argc, argv)
int argc;
{
rtx desc;
struct decision_head recog_tree, split_tree, peephole2_tree, h;
- FILE *infile;
- register int c;
progname = "genrecog";
- obstack_init (rtl_obstack);
memset (&recog_tree, 0, sizeof recog_tree);
memset (&split_tree, 0, sizeof split_tree);
if (argc <= 1)
fatal ("No input file name.");
- infile = fopen (argv[1], "r");
- if (infile == 0)
- {
- perror (argv[1]);
- return FATAL_EXIT_CODE;
- }
+ if (init_md_reader (argv[1]) != SUCCESS_EXIT_CODE)
+ return (FATAL_EXIT_CODE);
next_insn_code = 0;
next_index = 0;
while (1)
{
- c = read_skip_spaces (infile);
- if (c == EOF)
+ desc = read_md_rtx (&pattern_lineno, &next_insn_code);
+ if (desc == NULL)
break;
- ungetc (c, infile);
- desc = read_rtx (infile);
if (GET_CODE (desc) == DEFINE_INSN)
{
h = make_insn_sequence (desc, RECOG);
merge_trees (&peephole2_tree, &h);
}
- if (GET_CODE (desc) == DEFINE_PEEPHOLE
- || GET_CODE (desc) == DEFINE_EXPAND)
- next_insn_code++;
next_index++;
}
+ if (error_count)
+ return FATAL_EXIT_CODE;
+
puts ("\n\n");
process_tree (&recog_tree, RECOG);
insn_name_ptr[code] = new;
}
\f
-char *
-xstrdup (input)
- const char *input;
-{
- register size_t len = strlen (input) + 1;
- register char *output = xmalloc (len);
- memcpy (output, input, len);
- return output;
-}
-
-PTR
-xrealloc (old, size)
- PTR old;
- size_t size;
-{
- register PTR ptr;
- if (old)
- ptr = (PTR) realloc (old, size);
- else
- ptr = (PTR) malloc (size);
- if (!ptr)
- fatal ("virtual memory exhausted");
- return ptr;
-}
-
-PTR
-xmalloc (size)
- size_t size;
-{
- register PTR val = (PTR) malloc (size);
-
- if (val == 0)
- fatal ("virtual memory exhausted");
- return val;
-}
-\f
static void
debug_decision_2 (test)
struct decision_test *test;
debug_decision_2 (test);
}
}
- fprintf (stderr, "} %d\n", d->number);
+ fprintf (stderr, "} %d n %d a %d\n", d->number,
+ (d->next ? d->next->number : -1),
+ (d->afterward ? d->afterward->number : -1));
}
static void