Commit 74f0c611 by Richard Henderson Committed by Richard Henderson

re PR inline-asm/15740 (ICE caused by a memory operand in an asm statement)

	PR inline-asm/15740
        * gimplify.c (gimplify_asm_expr): Move resolve asm names ...
        * c-typeck.c (build_asm_expr): ... here.  Validate input
        constraints.  Mark memory inputs addressable.

        * semantics.c (finish_asm_stmt): Resolve asm names.  Validate input
        constraints.  Mark memory inputs addressable.

From-SVN: r92693
parent 85f3cc42
2004-12-28 Richard Henderson <rth@redhat.com>
PR inline-asm/15740
* gimplify.c (gimplify_asm_expr): Move resolve asm names ...
* c-typeck.c (build_asm_expr): ... here. Validate input
constraints. Mark memory inputs addressable.
2004-12-28 Hans-Peter Nilsson <hp@bitrange.com>
PR target/18321
......
......@@ -6287,47 +6287,74 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
tree args;
int i;
const char *constraint;
const char **oconstraints;
bool allows_mem, allows_reg, is_inout;
int ninputs;
int noutputs;
int ninputs, noutputs;
ninputs = list_length (inputs);
noutputs = list_length (outputs);
oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
string = resolve_asm_operand_names (string, outputs, inputs);
/* Remove output conversions that change the type but not the mode. */
for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
{
tree output = TREE_VALUE (tail);
/* ??? Really, this should not be here. Users should be using a
proper lvalue, dammit. But there's a long history of using casts
in the output operands. In cases like longlong.h, this becomes a
primitive form of typechecking -- if the cast can be removed, then
the output operand had a type of the proper width; otherwise we'll
get an error. Gross, but ... */
STRIP_NOPS (output);
TREE_VALUE (tail) = output;
lvalue_or_else (output, lv_asm);
if (!lvalue_or_else (output, lv_asm))
output = error_mark_node;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
oconstraints[i] = constraint;
if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
&allows_mem, &allows_reg, &is_inout))
{
/* By marking this operand as erroneous, we will not try
to process this operand again in expand_asm_operands. */
TREE_VALUE (tail) = error_mark_node;
continue;
}
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
&allows_mem, &allows_reg, &is_inout))
{
/* If the operand is going to end up in memory,
mark it addressable. */
if (!allows_reg && !c_mark_addressable (output))
output = error_mark_node;
}
else
output = error_mark_node;
/* If the operand is a DECL that is going to end up in
memory, assume it is addressable. This is a bit more
conservative than it would ideally be; the exact test is
buried deep in expand_asm_operands and depends on the
DECL_RTL for the OPERAND -- which we don't have at this
point. */
if (!allows_reg && DECL_P (output))
c_mark_addressable (output);
TREE_VALUE (tail) = output;
}
/* Perform default conversions on array and function inputs.
Don't do this for other types as it would screw up operands
expected to be in memory. */
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
{
tree input;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
input = TREE_VALUE (tail);
input = default_function_array_conversion (input);
if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
oconstraints, &allows_mem, &allows_reg))
{
/* If the operand is going to end up in memory,
mark it addressable. */
if (!allows_reg && allows_mem && !c_mark_addressable (input))
input = error_mark_node;
}
else
input = error_mark_node;
TREE_VALUE (tail) = input;
}
args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
......@@ -6337,6 +6364,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
ASM_VOLATILE_P (args) = 1;
ASM_INPUT_P (args) = 1;
}
return args;
}
......
2004-12-28 Richard Henderson <rth@redhat.com>
PR inline-asm/15740
* semantics.c (finish_asm_stmt): Resolve asm names. Validate input
constraints. Mark memory inputs addressable.
2004-12-27 Jason Merrill <jason@redhat.com>
* decl.c (expand_static_init): Don't use shortcut if
......
......@@ -1139,62 +1139,80 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands,
if (!processing_template_decl)
{
int ninputs, noutputs;
const char *constraint;
const char **oconstraints;
bool allows_mem, allows_reg, is_inout;
tree operand;
int i;
int ninputs;
int noutputs;
for (t = input_operands; t; t = TREE_CHAIN (t))
ninputs = list_length (input_operands);
noutputs = list_length (output_operands);
oconstraints = (const char **) alloca (noutputs * sizeof (char *));
string = resolve_asm_operand_names (string, output_operands,
input_operands);
for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
{
tree converted_operand
= decay_conversion (TREE_VALUE (t));
operand = TREE_VALUE (t);
/* ??? Really, this should not be here. Users should be using a
proper lvalue, dammit. But there's a long history of using
casts in the output operands. In cases like longlong.h, this
becomes a primitive form of typechecking -- if the cast can be
removed, then the output operand had a type of the proper width;
otherwise we'll get an error. Gross, but ... */
STRIP_NOPS (operand);
if (!lvalue_or_else (operand, lv_asm))
operand = error_mark_node;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
&allows_mem, &allows_reg, &is_inout))
{
/* If the operand is going to end up in memory,
mark it addressable. */
if (!allows_reg && !cxx_mark_addressable (operand))
operand = error_mark_node;
}
else
operand = error_mark_node;
TREE_VALUE (t) = operand;
}
for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
{
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
operand = decay_conversion (TREE_VALUE (t));
/* If the type of the operand hasn't been determined (e.g.,
because it involves an overloaded function), then issue
an error message. There's no context available to
resolve the overloading. */
if (TREE_TYPE (converted_operand) == unknown_type_node)
if (TREE_TYPE (operand) == unknown_type_node)
{
error ("type of asm operand %qE could not be determined",
TREE_VALUE (t));
converted_operand = error_mark_node;
operand = error_mark_node;
}
TREE_VALUE (t) = converted_operand;
}
ninputs = list_length (input_operands);
noutputs = list_length (output_operands);
for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
{
bool allows_mem;
bool allows_reg;
bool is_inout;
const char *constraint;
tree operand;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
operand = TREE_VALUE (t);
if (!parse_output_constraint (&constraint,
i, ninputs, noutputs,
&allows_mem,
&allows_reg,
&is_inout))
if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
oconstraints, &allows_mem, &allows_reg))
{
/* By marking this operand as erroneous, we will not try
to process this operand again in expand_asm_operands. */
TREE_VALUE (t) = error_mark_node;
continue;
/* If the operand is going to end up in memory,
mark it addressable. */
if (!allows_reg && allows_mem && !cxx_mark_addressable (operand))
operand = error_mark_node;
}
else
operand = error_mark_node;
/* If the operand is a DECL that is going to end up in
memory, assume it is addressable. This is a bit more
conservative than it would ideally be; the exact test is
buried deep in expand_asm_operands and depends on the
DECL_RTL for the OPERAND -- which we don't have at this
point. */
if (!allows_reg && DECL_P (operand))
cxx_mark_addressable (operand);
TREE_VALUE (t) = operand;
}
}
......
......@@ -3262,10 +3262,6 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
bool allows_mem, allows_reg, is_inout;
enum gimplify_status ret, tret;
ASM_STRING (expr)
= resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
ASM_INPUTS (expr));
ret = GS_ALL_DONE;
for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link))
{
......
/* PR inline-asm/15740 */
/* { dg-do compile } */
/* { dg-options "-O" } */
void foo(void)
{
int a, b;
a = 1;
b = a + 1;
asm ("" : : "m" (a));
}
/* PR inline-asm/15740 */
/* { dg-do compile } */
/* { dg-options "-O" } */
void foo(void)
{
int a, b;
a = 1;
b = a + 1;
asm ("" : : "m" (a));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment