This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Better constraint checking for asms
- To: egcs-patches at cygnus dot com
- Subject: Better constraint checking for asms
- From: Bernd Schmidt <crux at pool dot informatik dot rwth-aachen dot de>
- Date: Tue, 6 Oct 1998 16:00:28 +0200 (MET DST)
This patch moves some of the checks for asm statement constraints out of
find_reloads and into stmt.c. This has the following advantages:
- it's more deterministic. find_reloads never gets called for a dead
asm statement that got removed, and it may be called multiple times for
a live asm statement.
- find_reloads can't determine all possible errors. One subtle problem
is to detect an asm of the form
__asm__ ("" : "+r" (x) : "r%" (y))
where "%" is mentioned in the last written asm operand, but not in the
resulting pattern which has one more input operand to match the in-out
operand.
- find_reloads isn't the only function that might want to examine asm
operands, and it's best to do the checks before emitting incorrect rtl.
I've added an additional check that verifies that "+" and "=" are always
at the beginning of the constraint string for an output.
Bernd
Test program which should give errors for all asms (is there a way to
describe this as a c-torture test?):
int t ()
{
int x, y;
__asm__ ("" : "r" (x) :);
__asm__ ("" : "r=" (x) :);
__asm__ ("" : "r+" (x) :);
__asm__ ("" : "=r=" (x) :);
__asm__ ("" : "=r+" (x) :);
__asm__ ("" : "=r%" (x) :);
__asm__ ("" : : "r%" (x));
__asm__ ("" : "+r" (x), "=r%" (y) :);
__asm__ ("" : "+r" (x) : "r%" (y));
__asm__ ("" : "=r" (x) : "=r" (y));
__asm__ ("" : "=r" (x) : "&r" (y));
__asm__ ("" : "=r" (x) : "+r" (y));
__asm__ ("" : "=r" (x) : "r,r" (y));
}
* stmt.c (n_occurrences): New static function.
(expand_asm_operands): Verify that all constrains match in the
number of alternatives.
Verify that '+' or '=' are at the beginning of an output constraint.
Don't allow '&' for input operands.
Verify that '%' isn't written for the last operand.
* reload.c (find_reloads): Abort if an asm is found with invalid
constraints; all possible problems ought to be checked for earlier.
Index: stmt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/stmt.c,v
retrieving revision 1.47
diff -u -p -r1.47 stmt.c
--- stmt.c 1998/08/24 09:27:39 1.47
+++ stmt.c 1998/10/06 13:11:09
@@ -425,6 +425,7 @@ struct label_chain
static int using_eh_for_cleanups_p = 0;
+static int n_occurrences PROTO((int, char *));
static void expand_goto_internal PROTO((tree, rtx, rtx));
static int expand_fixup PROTO((tree, rtx, rtx));
static void fixup_gotos PROTO((struct nesting *, rtx, tree,
@@ -1096,8 +1097,18 @@ fixup_gotos (thisblock, stack_level, cle
f->stack_level = stack_level;
}
}
-
-
+
+/* Return the number of times character C occurs in string S. */
+static int
+n_occurrences (c, s)
+ int c;
+ char *s;
+{
+ int n = 0;
+ while (*s)
+ n += (*s++ == c);
+ return n;
+}
/* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text,
@@ -1184,13 +1196,38 @@ expand_asm_operands (string, outputs, in
last_expr_type = 0;
+ /* Check that the number of alternatives is constant across all
+ operands. */
+ if (outputs || inputs)
+ {
+ tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
+ int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp));
+ tree next = inputs;
+
+ tmp = outputs;
+ while (tmp)
+ {
+ char *constraint = TREE_STRING_POINTER (TREE_PURPOSE (tmp));
+ if (n_occurrences (',', constraint) != nalternatives)
+ {
+ error ("operand constraints for `asm' differ in number of alternatives");
+ return;
+ }
+ if (TREE_CHAIN (tmp))
+ tmp = TREE_CHAIN (tmp);
+ else
+ tmp = next, next = 0;
+ }
+ }
+
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
{
tree val = TREE_VALUE (tail);
tree type = TREE_TYPE (val);
+ char *constraint;
+ int c_len;
int j;
- int found_equal = 0;
- int found_plus = 0;
+ int is_inout = 0;
int allows_reg = 0;
/* If there's an erroneous arg, emit no insn. */
@@ -1201,28 +1238,44 @@ expand_asm_operands (string, outputs, in
if it allows any register. Be liberal on the latter test, since
the worst that happens if we get it wrong is we issue an error
message. */
+
+ c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1;
+ constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+
+ if (c_len == 0
+ || (constraint[0] != '=' && constraint[0] != '+'))
+ {
+ error ("output operand constraint lacks `='");
+ return;
+ }
+
+ is_inout = constraint[0] == '+';
+ /* Replace '+' with '='. */
+ constraint[0] = '=';
+ /* Make sure we can specify the matching operand. */
+ if (is_inout && i > 9)
+ {
+ error ("output operand constraint %d contains `+'", i);
+ return;
+ }
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
+ for (j = 1; j < c_len; j++)
+ switch (constraint[j])
{
case '+':
- /* Make sure we can specify the matching operand. */
- if (i > 9)
+ case '=':
+ error ("operand constraint contains '+' or '=' at illegal position.");
+ return;
+
+ case '%':
+ if (i + 1 == ninputs + noutputs)
{
- error ("output operand constraint %d contains `+'", i);
+ error ("`%%' constraint used with last operand");
return;
}
-
- /* Replace '+' with '='. */
- TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] = '=';
- found_plus = 1;
break;
- case '=':
- found_equal = 1;
- break;
-
- case '?': case '!': case '*': case '%': case '&':
+ case '?': case '!': case '*': case '&':
case 'V': case 'm': case 'o': case '<': case '>':
case 'E': case 'F': case 'G': case 'H': case 'X':
case 's': case 'i': case 'n':
@@ -1244,12 +1297,6 @@ expand_asm_operands (string, outputs, in
break;
}
- if (! found_equal && ! found_plus)
- {
- error ("output operand constraint lacks `='");
- return;
- }
-
/* If an output operand is not a decl or indirect ref and our constraint
allows a register, make a temporary to act as an intermediate.
Make the asm insn write into that, then our caller will copy it to
@@ -1260,7 +1307,7 @@ expand_asm_operands (string, outputs, in
&& ! (GET_CODE (DECL_RTL (val)) == REG
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
|| ! allows_reg
- || found_plus)
+ || is_inout)
{
if (! allows_reg)
mark_addressable (TREE_VALUE (tail));
@@ -1278,7 +1325,7 @@ expand_asm_operands (string, outputs, in
TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
}
- if (found_plus)
+ if (is_inout)
{
inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
inout_opnum[ninout++] = i;
@@ -1311,12 +1358,16 @@ expand_asm_operands (string, outputs, in
{
int j;
int allows_reg = 0;
+ char *constraint;
+ int c_len;
/* If there's an erroneous arg, emit no insn,
because the ASM_INPUT would get VOIDmode
and that could cause a crash in reload. */
if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
return;
+
+ /* ??? Can this happen, and does the error message make any sense? */
if (TREE_PURPOSE (tail) == NULL_TREE)
{
error ("hard register `%s' listed as input operand to `asm'",
@@ -1324,17 +1375,27 @@ expand_asm_operands (string, outputs, in
return;
}
- /* Make sure constraint has neither `=' nor `+'. */
+ c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1;
+ constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
+ /* Make sure constraint has neither `=', `+', nor '&'. */
+
+ for (j = 0; j < c_len; j++)
+ switch (constraint[j])
{
- case '+': case '=':
- error ("input operand constraint contains `%c'",
- TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]);
+ case '+': case '=': case '&':
+ error ("input operand constraint contains `%c'", constraint[j]);
return;
- case '?': case '!': case '*': case '%': case '&':
+ case '%':
+ if (i + 1 == ninputs - ninout)
+ {
+ error ("`%%' constraint used with last operand");
+ return;
+ }
+ break;
+
+ case '?': case '!': case '*':
case 'V': case 'm': case 'o': case '<': case '>':
case 'E': case 'F': case 'G': case 'H': case 'X':
case 's': case 'i': case 'n':
@@ -1352,8 +1413,7 @@ expand_asm_operands (string, outputs, in
operands to memory. */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]
- >= '0' + noutputs)
+ if (constraint[j] >= '0' + noutputs)
{
error
("matching constraint references invalid operand number");
@@ -1398,10 +1458,10 @@ expand_asm_operands (string, outputs, in
emit_move_insn (memloc, XVECEXP (body, 3, i));
XVECEXP (body, 3, i) = memloc;
}
-
+
XVECEXP (body, 4, i) /* constraints */
= gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
- TREE_STRING_POINTER (TREE_PURPOSE (tail)));
+ constraint);
i++;
}
Index: reload.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/reload.c,v
retrieving revision 1.46
diff -u -p -r1.46 reload.c
--- reload.c 1998/09/24 10:51:35 1.46
+++ reload.c 1998/10/06 13:11:12
@@ -2442,15 +2442,6 @@ find_reloads (insn, replace, ind_levels,
bcopy ((char *) constraints, (char *) constraints1,
noperands * sizeof (char *));
n_alternatives = n_occurrences (',', constraints[0]) + 1;
- for (i = 1; i < noperands; i++)
- if (n_alternatives != n_occurrences (',', constraints[i]) + 1)
- {
- error_for_asm (insn, "operand constraints differ in number of alternatives");
- /* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
- n_reloads = 0;
- return;
- }
}
break;
}
@@ -2510,15 +2501,9 @@ find_reloads (insn, replace, ind_levels,
{
/* The last operand should not be marked commutative. */
if (i == noperands - 1)
- {
- if (this_insn_is_asm)
- warning_for_asm (this_insn,
- "`%%' constraint used with last operand");
- else
- abort ();
- }
- else
- commutative = i;
+ abort ();
+
+ commutative = i;
}
else if (c >= '0' && c <= '9')
{
@@ -2528,13 +2513,7 @@ find_reloads (insn, replace, ind_levels,
/* An operand may not match itself. */
if (c == i)
- {
- if (this_insn_is_asm)
- warning_for_asm (this_insn,
- "operand %d has constraint %d", i, c);
- else
- abort ();
- }
+ abort ();
/* If C can be commuted with C+1, and C might need to match I,
then C+1 might also need to match I. */
@@ -3372,14 +3351,7 @@ find_reloads (insn, replace, ind_levels,
early_data = decompose (recog_operand[i]);
if (modified[i] == RELOAD_READ)
- {
- if (this_insn_is_asm)
- warning_for_asm (this_insn,
- "`&' constraint used with input operand");
- else
- abort ();
- continue;
- }
+ abort ();
if (this_alternative[i] == NO_REGS)
{