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;
}
{
/* 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')
{
/* 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. */
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)
{
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,
f->stack_level = stack_level;
}
}
-
-
+\f
+/* 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;
+}
\f
/* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text,
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. */
the worst that happens if we get it wrong is we issue an error
message. */
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
+ 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 = 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':
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
&& ! (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));
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;
{
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'",
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':
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");
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++;
}