stmt.c (n_occurrences): New static function.
* 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. From-SVN: r22911
This commit is contained in:
parent
f1da172943
commit
2a230e9dc4
@ -1,3 +1,14 @@
|
||||
Thu Oct 8 05:05:34 1998 Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>
|
||||
|
||||
* 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.
|
||||
|
||||
Thu Oct 8 04:26:20 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* flags.h (flag_branch_on_count_reg): Always declare
|
||||
|
38
gcc/reload.c
38
gcc/reload.c
@ -2442,15 +2442,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
||||
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, live_known, reload_reg_p)
|
||||
{
|
||||
/* 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, live_known, reload_reg_p)
|
||||
|
||||
/* 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, live_known, reload_reg_p)
|
||||
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)
|
||||
{
|
||||
|
133
gcc/stmt.c
133
gcc/stmt.c
@ -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, cleanup_list, first_insn, dont_jump_in)
|
||||
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 +1195,38 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
|
||||
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. */
|
||||
@ -1202,27 +1238,43 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
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':
|
||||
@ -1244,12 +1296,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
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 +1306,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
&& ! (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 +1324,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
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 +1357,16 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
{
|
||||
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 +1374,27 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
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 +1412,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
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 +1457,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|
||||
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++;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user