pr 4299 fix for mainline
Richard Henderson
rth@redhat.com
Sun Dec 23 22:17:00 GMT 2001
I've been somewhat delinquent forward porting this patch
from the 3.0 branch.
r~
* stmt.c (parse_input_constraint): Break out from ...
(expand_asm_operands): ... here. Loop over the operands twice,
the first time only calling mark_addressable. Correct and simplify
the conditions for spilling an output operand to memory.
* gcc.c-torture/compile/20011205-1.c: New.
Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.238
diff -c -p -d -r1.238 stmt.c
*** stmt.c 2001/12/12 12:44:46 1.238
--- stmt.c 2001/12/24 05:53:47
*************** struct stmt_status
*** 397,402 ****
--- 397,405 ----
static int using_eh_for_cleanups_p = 0;
static int n_occurrences PARAMS ((int, const char *));
+ static bool parse_input_constraint PARAMS ((const char **, int, int, int,
+ int, const char * const *,
+ bool *, bool *));
static void expand_goto_internal PARAMS ((tree, rtx, rtx));
static int expand_fixup PARAMS ((tree, rtx, rtx));
static rtx expand_nl_handler_label PARAMS ((rtx, rtx));
*************** expand_asm (body)
*** 1307,1319 ****
Returns TRUE if all went well; FALSE if an error occurred. */
bool
! parse_output_constraint (constraint_p,
! operand_num,
! ninputs,
! noutputs,
! allows_mem,
! allows_reg,
! is_inout)
const char **constraint_p;
int operand_num;
int ninputs;
--- 1310,1317 ----
Returns TRUE if all went well; FALSE if an error occurred. */
bool
! parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
! allows_mem, allows_reg, is_inout)
const char **constraint_p;
int operand_num;
int ninputs;
*************** parse_output_constraint (constraint_p,
*** 1444,1449 ****
--- 1442,1572 ----
return true;
}
+ /* Similar, but for input constraints. */
+
+ static bool
+ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
+ constraints, allows_mem, allows_reg)
+ const char **constraint_p;
+ int input_num;
+ int ninputs;
+ int noutputs;
+ int ninout;
+ const char * const * constraints;
+ bool *allows_mem;
+ bool *allows_reg;
+ {
+ const char *constraint = *constraint_p;
+ const char *orig_constraint = constraint;
+ size_t c_len = strlen (constraint);
+ size_t j;
+
+ /* Assume the constraint doesn't allow the use of either
+ a register or memory. */
+ *allows_mem = false;
+ *allows_reg = false;
+
+ /* Make sure constraint has neither `=', `+', nor '&'. */
+
+ for (j = 0; j < c_len; j++)
+ switch (constraint[j])
+ {
+ case '+': case '=': case '&':
+ if (constraint == orig_constraint)
+ {
+ error ("input operand constraint contains `%c'", constraint[j]);
+ return false;
+ }
+ break;
+
+ case '%':
+ if (constraint == orig_constraint
+ && input_num + 1 == ninputs - ninout)
+ {
+ error ("`%%' constraint used with last operand");
+ return false;
+ }
+ break;
+
+ case 'V': case 'm': case 'o':
+ *allows_mem = true;
+ break;
+
+ case '<': case '>':
+ case '?': case '!': case '*': case '#':
+ case 'E': case 'F': case 'G': case 'H':
+ case 's': case 'i': case 'n':
+ case 'I': case 'J': case 'K': case 'L': case 'M':
+ case 'N': case 'O': case 'P': case ',':
+ break;
+
+ /* Whether or not a numeric constraint allows a register is
+ decided by the matching constraint, and so there is no need
+ to do anything special with them. We must handle them in
+ the default case, so that we don't unnecessarily force
+ operands to memory. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ char *end;
+ unsigned long match;
+
+ match = strtoul (constraint + j, &end, 10);
+ if (match >= (unsigned long) noutputs)
+ {
+ error ("matching constraint references invalid operand number");
+ return false;
+ }
+
+ /* Try and find the real constraint for this dup. Only do this
+ if the matching constraint is the only alternative. */
+ if (*end == '\0'
+ && (j == 0 || (j == 1 && constraint[0] == '%')))
+ {
+ constraint = constraints[match];
+ *constraint_p = constraint;
+ c_len = strlen (constraint);
+ j = 0;
+ break;
+ }
+ else
+ j = end - constraint;
+ }
+ /* Fall through. */
+
+ case 'p': case 'r':
+ *allows_reg = true;
+ break;
+
+ case 'g': case 'X':
+ *allows_reg = true;
+ *allows_mem = true;
+ break;
+
+ default:
+ if (! ISALPHA (constraint[j]))
+ {
+ error ("invalid punctuation `%c' in constraint", constraint[j]);
+ return false;
+ }
+ if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
+ *allows_reg = true;
+ #ifdef EXTRA_CONSTRAINT
+ else
+ {
+ /* Otherwise we can't assume anything about the nature of
+ the constraint except that it isn't purely registers.
+ Treat it like "g" and hope for the best. */
+ *allows_reg = true;
+ *allows_mem = true;
+ }
+ #endif
+ break;
+ }
+
+ return true;
+ }
+
/* Generate RTL for an asm statement with arguments.
STRING is the instruction template.
OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
*************** expand_asm_operands (string, outputs, in
*** 1472,1478 ****
rtx body;
int ninputs = list_length (inputs);
int noutputs = list_length (outputs);
! int ninout = 0;
int nclobbers;
tree tail;
int i;
--- 1595,1601 ----
rtx body;
int ninputs = list_length (inputs);
int noutputs = list_length (outputs);
! int ninout;
int nclobbers;
tree tail;
int i;
*************** expand_asm_operands (string, outputs, in
*** 1524,1533 ****
--- 1647,1661 ----
last_expr_type = 0;
+ /* First pass over inputs and outputs checks validity and sets
+ mark_addressable if needed. */
+
+ ninout = 0;
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
{
tree val = TREE_VALUE (tail);
tree type = TREE_TYPE (val);
+ const char *constraint;
bool is_inout;
bool allows_reg;
bool allows_mem;
*************** expand_asm_operands (string, outputs, in
*** 1536,1557 ****
if (type == error_mark_node)
return;
- /* Make sure constraint has `=' and does not have `+'. Also, see
- 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. */
-
/* Try to parse the output constraint. If that fails, there's
no point in going further. */
! if (!parse_output_constraint (&constraints[i],
! i,
! ninputs,
! noutputs,
! &allows_mem,
! &allows_reg,
! &is_inout))
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
--- 1664,1730 ----
if (type == error_mark_node)
return;
/* Try to parse the output constraint. If that fails, there's
no point in going further. */
! constraint = constraints[i];
! if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
! &allows_mem, &allows_reg, &is_inout))
! return;
!
! if (! allows_reg
! && (allows_mem
! || is_inout
! || (DECL_P (val)
! && GET_CODE (DECL_RTL (val)) == REG
! && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
! mark_addressable (val);
!
! if (is_inout)
! ninout++;
! }
!
! ninputs += ninout;
! if (ninputs + noutputs > MAX_RECOG_OPERANDS)
! {
! error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
! return;
! }
!
! for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail))
! {
! bool allows_reg, allows_mem;
! const char *constraint;
!
! /* 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;
!
! constraint = constraints[i + noutputs];
! if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
! constraints, &allows_mem, &allows_reg))
return;
+ if (! allows_reg && allows_mem)
+ mark_addressable (TREE_VALUE (tail));
+ }
+
+ /* Second pass evaluates arguments. */
+
+ ninout = 0;
+ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ {
+ tree val = TREE_VALUE (tail);
+ tree type = TREE_TYPE (val);
+ bool is_inout;
+ bool allows_reg;
+ bool allows_mem;
+
+ if (!parse_output_constraint (&constraints[i], i, ninputs,
+ noutputs, &allows_mem, &allows_reg,
+ &is_inout))
+ abort ();
+
/* 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
*************** expand_asm_operands (string, outputs, in
*** 1569,1580 ****
|| ! allows_reg
|| is_inout)
{
! if (! allows_reg)
! mark_addressable (TREE_VALUE (tail));
!
! output_rtx[i]
! = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
! EXPAND_WRITE);
if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
error ("output number %d not directly addressable", i);
--- 1742,1748 ----
|| ! allows_reg
|| is_inout)
{
! output_rtx[i] = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
error ("output number %d not directly addressable", i);
*************** expand_asm_operands (string, outputs, in
*** 1597,1614 ****
if (is_inout)
{
! inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
inout_opnum[ninout++] = i;
}
}
- ninputs += ninout;
- if (ninputs + noutputs > MAX_RECOG_OPERANDS)
- {
- error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
- return;
- }
-
/* Make vectors for the expression-rtx, constraint strings,
and named operands. */
--- 1765,1775 ----
if (is_inout)
{
! inout_mode[ninout] = TYPE_MODE (type);
inout_opnum[ninout++] = i;
}
}
/* Make vectors for the expression-rtx, constraint strings,
and named operands. */
*************** expand_asm_operands (string, outputs, in
*** 1628,1781 ****
for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
{
! int j;
! int allows_reg = 0, allows_mem = 0;
! const char *constraint, *orig_constraint;
! int c_len;
rtx op;
-
- /* 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'",
- TREE_STRING_POINTER (TREE_VALUE (tail)) );
- return;
- }
-
- orig_constraint = constraint = constraints[i + noutputs];
- c_len = strlen (constraint);
-
- /* Make sure constraint has neither `=', `+', nor '&'. */
-
- for (j = 0; j < c_len; j++)
- switch (constraint[j])
- {
- case '+': case '=': case '&':
- if (constraint == orig_constraint)
- {
- error ("input operand constraint contains `%c'",
- constraint[j]);
- return;
- }
- break;
-
- case '%':
- if (constraint == orig_constraint
- && i + 1 == ninputs - ninout)
- {
- error ("`%%' constraint used with last operand");
- return;
- }
- break;
-
- case 'V': case 'm': case 'o':
- allows_mem = 1;
- break;
-
- case '<': case '>':
- case '?': case '!': case '*': case '#':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',':
- break;
-
- /* Whether or not a numeric constraint allows a register is
- decided by the matching constraint, and so there is no need
- to do anything special with them. We must handle them in
- the default case, so that we don't unnecessarily force
- operands to memory. */
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- char *end;
- unsigned long match;
-
- match = strtoul (constraint + j, &end, 10);
- if (match >= (unsigned long) noutputs)
- {
- error ("matching constraint references invalid operand number");
- return;
- }
-
- /* Try and find the real constraint for this dup. Only do
- this if the matching constraint is the only alternative. */
- if (*end == '\0'
- && (j == 0 || (j == 1 && constraint[0] == '%')))
- {
- constraint = constraints[match];
- c_len = strlen (constraint);
- j = 0;
- break;
- }
- else
- j = end - constraint;
- }
- /* Fall through. */
! case 'p': case 'r':
! allows_reg = 1;
! break;
!
! case 'g': case 'X':
! allows_reg = 1;
! allows_mem = 1;
! break;
!
! default:
! if (! ISALPHA (constraint[j]))
! {
! error ("invalid punctuation `%c' in constraint",
! constraint[j]);
! return;
! }
! if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
! allows_reg = 1;
! #ifdef EXTRA_CONSTRAINT
! else
! {
! /* Otherwise we can't assume anything about the nature of
! the constraint except that it isn't purely registers.
! Treat it like "g" and hope for the best. */
! allows_reg = 1;
! allows_mem = 1;
! }
! #endif
! break;
! }
! if (! allows_reg && allows_mem)
! mark_addressable (TREE_VALUE (tail));
! op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
/* Never pass a CONCAT to an ASM. */
- generating_concat_p = 0;
if (GET_CODE (op) == CONCAT)
op = force_reg (GET_MODE (op), op);
if (asm_operand_ok (op, constraint) <= 0)
{
if (allows_reg)
! op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
else if (!allows_mem)
warning ("asm operand %d probably doesn't match constraints",
i + noutputs);
else if (CONSTANT_P (op))
! op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
! op);
else if (GET_CODE (op) == REG
|| GET_CODE (op) == SUBREG
|| GET_CODE (op) == ADDRESSOF
|| GET_CODE (op) == CONCAT)
{
- tree type = TREE_TYPE (TREE_VALUE (tail));
tree qual_type = build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST));
--- 1789,1828 ----
for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
{
! bool allows_reg, allows_mem;
! const char *constraint;
! tree val, type;
rtx op;
! constraint = constraints[i + noutputs];
! if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
! constraints, &allows_mem, &allows_reg))
! abort ();
! generating_concat_p = 0;
! val = TREE_VALUE (tail);
! type = TREE_TYPE (val);
! op = expand_expr (val, NULL_RTX, VOIDmode, 0);
/* Never pass a CONCAT to an ASM. */
if (GET_CODE (op) == CONCAT)
op = force_reg (GET_MODE (op), op);
if (asm_operand_ok (op, constraint) <= 0)
{
if (allows_reg)
! op = force_reg (TYPE_MODE (type), op);
else if (!allows_mem)
warning ("asm operand %d probably doesn't match constraints",
i + noutputs);
else if (CONSTANT_P (op))
! op = force_const_mem (TYPE_MODE (type), op);
else if (GET_CODE (op) == REG
|| GET_CODE (op) == SUBREG
|| GET_CODE (op) == ADDRESSOF
|| GET_CODE (op) == CONCAT)
{
tree qual_type = build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST));
*************** expand_asm_operands (string, outputs, in
*** 1786,1794 ****
}
else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
! /* We won't recognize volatile memory as available a
! memory_operand at this point. Ignore it. */
! ;
else if (queued_subexp_p (op))
;
else
--- 1833,1842 ----
}
else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
! {
! /* We won't recognize volatile memory as available a
! memory_operand at this point. Ignore it. */
! }
else if (queued_subexp_p (op))
;
else
*************** expand_asm_operands (string, outputs, in
*** 1798,1809 ****
warning ("asm operand %d probably doesn't match constraints",
i + noutputs);
}
generating_concat_p = old_generating_concat_p;
ASM_OPERANDS_INPUT (body, i) = op;
ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
! = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
! orig_constraint);
}
/* Protect all the operands from the queue now that they have all been
--- 1846,1857 ----
warning ("asm operand %d probably doesn't match constraints",
i + noutputs);
}
+
generating_concat_p = old_generating_concat_p;
ASM_OPERANDS_INPUT (body, i) = op;
ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
! = gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
}
/* Protect all the operands from the queue now that they have all been
More information about the Gcc-patches
mailing list