aboutsummaryrefslogtreecommitdiff
path: root/gcc/genrecog.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>1999-10-14 02:37:31 -0700
committerRichard Henderson <rth@gcc.gnu.org>1999-10-14 02:37:31 -0700
commit8fe0ca0c076f46ba45448b3254597844475eee30 (patch)
tree1796e42498ad521d8d7c76c8890bd5c76139a8cf /gcc/genrecog.c
parent03e0a65f6e0a4bd3e292e1e6a8328a591ec86f58 (diff)
downloadgcc-8fe0ca0c076f46ba45448b3254597844475eee30.zip
gcc-8fe0ca0c076f46ba45448b3254597844475eee30.tar.gz
gcc-8fe0ca0c076f46ba45448b3254597844475eee30.tar.bz2
genrecog.c (special_mode_pred_table): New.
* genrecog.c (special_mode_pred_table): New. (NUM_SPECIAL_MODE_PREDS): New. (find_operand): New. (validate_pattern): New argument `insn'. Warn for assignment to any predicate accepting non-lvalues. Conditionaly warn for match_operand without a mode. Try much harder to match source and destination modes on a set. * tm.texi (SPECIAL_MODE_PREDICATES): Document. From-SVN: r29967
Diffstat (limited to 'gcc/genrecog.c')
-rw-r--r--gcc/genrecog.c264
1 files changed, 207 insertions, 57 deletions
diff --git a/gcc/genrecog.c b/gcc/genrecog.c
index 251e5e9..f36e879 100644
--- a/gcc/genrecog.c
+++ b/gcc/genrecog.c
@@ -216,12 +216,24 @@ static struct pred_table
#define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0])
+static const char * special_mode_pred_table[] = {
+#ifdef SPECIAL_MODE_PREDICATES
+ SPECIAL_MODE_PREDICATES
+#endif
+ NULL
+};
+
+#define NUM_SPECIAL_MODE_PREDS \
+ (sizeof (special_mode_pred_table) / sizeof (const char *) - 1)
+
static struct decision *new_decision
PROTO((const char *, struct decision_head *));
static struct decision_test *new_decision_test
PROTO((enum decision_type, struct decision_test ***));
-static void validate_pattern
+static rtx find_operand
PROTO((rtx, int));
+static void validate_pattern
+ PROTO((rtx, rtx, int));
static struct decision *add_to_sequence
PROTO((rtx, struct decision_head *, const char *, enum routine_type, int));
@@ -356,66 +368,118 @@ new_decision_test (type, pplace)
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. */
static void
-validate_pattern (pattern, set_dest)
+validate_pattern (pattern, insn, set_dest)
rtx pattern;
+ rtx insn;
int set_dest;
{
const char *fmt;
RTX_CODE code;
- int i, j, len;
+ size_t i, len;
+ int j;
code = GET_CODE (pattern);
switch (code)
{
case MATCH_SCRATCH:
- case MATCH_INSN:
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)
{
- /* 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.
-
- 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. */
-
- for (i = 0; i < (int) NUM_KNOWN_PREDS; i++)
+ for (i = 0; i < NUM_KNOWN_PREDS; i++)
if (! strcmp (preds[i].name, pred_name))
break;
- if (i < (int) NUM_KNOWN_PREDS)
+ if (i < NUM_KNOWN_PREDS)
{
- int j, allows_const_int;
+ int j;
- allows_const_int = 0;
+ allows_non_lvalue = allows_non_const = 0;
for (j = 0; preds[i].codes[j] != 0; j++)
- if (preds[i].codes[j] == CONST_INT)
- {
- allows_const_int = 1;
- break;
- }
-
- if (allows_const_int && set_dest)
{
- message_with_line (pattern_lineno,
- "warning: `%s' accepts const_int,",
- pred_name);
- message_with_line (pattern_lineno,
- " and used as destination of a set");
+ 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
@@ -423,36 +487,123 @@ validate_pattern (pattern, set_dest)
#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);
+ 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;
+ }
+ }
+
+ /* 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_dest
+ && pred_name[0] != '\0'
+ && allows_non_lvalue)
+ {
+ message_with_line (pattern_lineno,
+ "warning: `%s' allows non-lvalue,",
+ pred_name);
+ message_with_line (pattern_lineno,
+ " and used as destination of a set");
+ }
+
+ /* 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. */
+
+ if (GET_MODE (pattern) == VOIDmode
+ && code == MATCH_OPERAND
+ && pred_name[0] != '\0'
+ && allows_non_const
+ && ! special_mode_pred
+ && strstr (c_test, "operands") != NULL
+ && GET_CODE (insn) == DEFINE_INSN)
+ {
+ message_with_line (pattern_lineno,
+ "warning: operand %d missing mode?",
+ XINT (pattern, 0));
}
return;
}
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")))
- {
- message_with_line (pattern_lineno,
- "mode mismatch in set: %smode vs %smode",
- GET_MODE_NAME (GET_MODE (SET_DEST (pattern))),
- GET_MODE_NAME (GET_MODE (SET_SRC (pattern))));
- error_count++;
- }
+ {
+ 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);
- validate_pattern (SET_DEST (pattern), 1);
- validate_pattern (SET_SRC (pattern), 0);
+ /* 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) != 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, 1);
+ validate_pattern (SET_DEST (pattern), insn, 1);
+ validate_pattern (SET_SRC (pattern), insn, 0);
+ return;
+ }
+
+ case CLOBBER:
+ validate_pattern (SET_DEST (pattern), insn, 1);
return;
-
+
case LABEL_REF:
if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
{
@@ -474,12 +625,12 @@ validate_pattern (pattern, set_dest)
switch (fmt[i])
{
case 'e': case 'u':
- validate_pattern (XEXP (pattern, i), 0);
+ validate_pattern (XEXP (pattern, i), insn, 0);
break;
case 'E':
for (j = 0; j < XVECLEN (pattern, i); j++)
- validate_pattern (XVECEXP (pattern, i, j), 0);
+ validate_pattern (XVECEXP (pattern, i, j), insn, 0);
break;
case 'i': case 'w': case '0': case 's':
@@ -489,7 +640,6 @@ validate_pattern (pattern, set_dest)
abort ();
}
}
-
}
/* Create a chain of nodes to verify that an rtl expression matches
@@ -2148,7 +2298,7 @@ make_insn_sequence (insn, type)
PUT_MODE (x, VOIDmode);
}
- validate_pattern (x, 0);
+ validate_pattern (x, insn, 0);
memset(&head, 0, sizeof(head));
last = add_to_sequence (x, &head, "", type, 1);