stmt.c (parse_input_constraint): Break out from ...

* 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.

From-SVN: r48298
This commit is contained in:
Richard Henderson 2001-12-23 21:57:02 -08:00
parent 99407cf2f1
commit 6be2e1f88c
3 changed files with 260 additions and 195 deletions

View File

@ -1,3 +1,10 @@
2001-12-23 Richard Henderson <rth@redhat.com>
* 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.
2001-12-23 Richard Henderson <rth@redhat.com>
* config/alpha/alpha.c (call_operand) [OSF]: Disallow virtual regs.
@ -46,13 +53,13 @@
2001-12-22 Aldy Hernandez <aldyh@redhat.com>
* config/rs6000/rs6000.h (rs6000_builtins): Add vsldoi variants.
* config/rs6000/rs6000.h (rs6000_builtins): Add vsldoi variants.
* config/rs6000/rs6000.md ("altivec_vsldoi_*"): Same.
* config/rs6000/rs6000.md ("altivec_vsldoi_*"): Same.
* config/rs6000/rs6000.c: Clean up some spacing and indentation.
(altivec_init_builtins): Add tree types for builtins with 4 bit
literals.
* config/rs6000/rs6000.c: Clean up some spacing and indentation.
(altivec_init_builtins): Add tree types for builtins with 4 bit
literals.
(bdesc_3arg): Add vsldoi variants.
2001-12-22 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
@ -248,16 +255,16 @@ Fri Dec 21 17:30:15 2001 Jeffrey A Law (law@redhat.com)
2001-12-20 Nick Clifton <nickc@cambridge.redhat.com>
* config/arm/arm.c (arm_compute_save_reg0_reg12_mask): New
function. Compute which of registers r0 through r12 should be
function. Compute which of registers r0 through r12 should be
saved onto the stack during a function's prologue.
(arm_compute_save_reg_mask): Use
arm_compute_save_reg0_reg12_mask.
(arm_compute_initial_elimination_offset): Use
arm_compute_save_reg0_reg12_mask.
(arm_compute_save_reg_mask): Use
arm_compute_save_reg0_reg12_mask.
(arm_compute_initial_elimination_offset): Use
arm_compute_save_reg0_reg12_mask.
(arm_expand_prologue): Do not mark as save of the IP register
for an interrupt handler as being part of the frame creation
code.
(arm_expand_prologue): Do not mark as save of the IP register
for an interrupt handler as being part of the frame creation
code.
2001-12-20 Richard Henderson <rth@redhat.com>
@ -320,30 +327,30 @@ Thu Dec 20 16:58:46 CET 2001 Jan Hubicka <jh@suse.cz>
2001-12-19 Aldy Hernandez <aldyh@redhat.com>
* doc/install.texi: Add documentation for --enable-altivec.
* doc/install.texi: Add documentation for --enable-altivec.
* config.gcc: Add support for --enable-altivec.
* config.gcc: Add support for --enable-altivec.
* config/rs6000/altivec.h: New.
* config/rs6000/altivec.h: New.
* config/rs6000/linuxaltivec.h (SUBSUBTARGET_OVERRIDE_OPTIONS):
Define. Fix typo.
* config/rs6000/linuxaltivec.h (SUBSUBTARGET_OVERRIDE_OPTIONS):
Define. Fix typo.
* config/rs6000/rs6000.c (vrsave_operation): Change unspec to
* config/rs6000/rs6000.c (vrsave_operation): Change unspec to
unspec_volatile.
(generate_set_vrsave): Generate the unspec here instead of calling
an .md pattern.
(generate_set_vrsave): Use gen_rtvec.
(rs6000_emit_prologue): Replace call to gen_get_vrsave with
gen_rtx_SET.
(generate_set_vrsave): Generate the unspec here instead of calling
an .md pattern.
(generate_set_vrsave): Use gen_rtvec.
(rs6000_emit_prologue): Replace call to gen_get_vrsave with
gen_rtx_SET.
* config/rs6000/rs6000.md ("*movsi_internal1"): Add constraints
* config/rs6000/rs6000.md ("*movsi_internal1"): Add constraints
for setting special registers.
("*set_vrsave_internal"): Use unspec_volatile.
("set_vrsave"): Remove.
("get_vrsave"): Remove.
("*set_vrsave_internal"): Use unspec_volatile.
("set_vrsave"): Remove.
("get_vrsave"): Remove.
* config/rs6000/rs6000.h (REG_CLASS_CONTENTS): Add vrsave to
* config/rs6000/rs6000.h (REG_CLASS_CONTENTS): Add vrsave to
SPECIAL_REGS.
2001-12-19 Bruce Korb <bkorb@gnu.org>

View File

@ -397,6 +397,9 @@ struct stmt_status
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));
@ -1307,13 +1310,8 @@ expand_asm (body)
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)
parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
allows_mem, allows_reg, is_inout)
const char **constraint_p;
int operand_num;
int ninputs;
@ -1444,6 +1442,131 @@ parse_output_constraint (constraint_p,
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.
@ -1472,7 +1595,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
rtx body;
int ninputs = list_length (inputs);
int noutputs = list_length (outputs);
int ninout = 0;
int ninout;
int nclobbers;
tree tail;
int i;
@ -1524,10 +1647,15 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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;
@ -1536,22 +1664,67 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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))
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
@ -1569,12 +1742,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|| ! 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);
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);
@ -1597,18 +1765,11 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (is_inout)
{
inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
inout_mode[ninout] = TYPE_MODE (type);
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. */
@ -1628,154 +1789,40 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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;
bool allows_reg, allows_mem;
const char *constraint;
tree val, type;
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;
constraint = constraints[i + noutputs];
if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
constraints, &allows_mem, &allows_reg))
abort ();
/* ??? 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;
}
generating_concat_p = 0;
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);
val = TREE_VALUE (tail);
type = TREE_TYPE (val);
op = expand_expr (val, 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);
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 (TREE_TYPE (TREE_VALUE (tail))),
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 type = TREE_TYPE (TREE_VALUE (tail));
tree qual_type = build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST));
@ -1786,9 +1833,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
}
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. */
;
{
/* We won't recognize volatile memory as available a
memory_operand at this point. Ignore it. */
}
else if (queued_subexp_p (op))
;
else
@ -1798,12 +1846,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
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);
= gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
}
/* Protect all the operands from the queue now that they have all been

View File

@ -0,0 +1,10 @@
/* Failure to mark_addressable all operands before evaluation means we
don't set up the proper temporaries, which leaves us with an asm that
doesn't match its contraints. */
long foo()
{
long x;
asm("" : "=r"(x) : "m"(x));
return x;
}