This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
fix inline-asm/15740
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 28 Dec 2004 17:25:25 -0800
- Subject: fix inline-asm/15740
Marks memory-only operands TREE_ADDRESSABLE early, plus shifts some
other constraint error detection earlier in compilation.
Tested on i686-linux.
r~
* 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.
Index: gcc/testsuite/g++.dg/opt/asm2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/opt/asm2.C
diff -N gcc/testsuite/g++.dg/opt/asm2.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/opt/asm2.C 29 Dec 2004 01:17:32 -0000
***************
*** 0 ****
--- 1,11 ----
+ /* PR inline-asm/15740 */
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+
+ void foo(void)
+ {
+ int a, b;
+ a = 1;
+ b = a + 1;
+ asm ("" : : "m" (a));
+ }
Index: gcc/testsuite/gcc.dg/asm-9.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/asm-9.c
diff -N gcc/testsuite/gcc.dg/asm-9.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/gcc.dg/asm-9.c 29 Dec 2004 01:17:32 -0000
***************
*** 0 ****
--- 1,11 ----
+ /* PR inline-asm/15740 */
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+
+ void foo(void)
+ {
+ int a, b;
+ a = 1;
+ b = a + 1;
+ asm ("" : : "m" (a));
+ }
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.405
diff -c -p -d -r1.405 c-typeck.c
*** gcc/c-typeck.c 21 Dec 2004 17:00:58 -0000 1.405
--- gcc/c-typeck.c 29 Dec 2004 01:17:33 -0000
*************** build_asm_expr (tree string, tree output
*** 6287,6333 ****
tree args;
int i;
const char *constraint;
bool allows_mem, allows_reg, is_inout;
! int ninputs;
! int noutputs;
ninputs = list_length (inputs);
noutputs = list_length (outputs);
/* 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);
STRIP_NOPS (output);
! TREE_VALUE (tail) = output;
! lvalue_or_else (output, lv_asm);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
! 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 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);
}
/* 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));
args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
--- 6287,6360 ----
tree args;
int i;
const char *constraint;
+ const char **oconstraints;
bool allows_mem, allows_reg, is_inout;
! 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);
!
! 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))
! {
! /* 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;
! 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 (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);
*************** build_asm_expr (tree string, tree output
*** 6337,6342 ****
--- 6364,6370 ----
ASM_VOLATILE_P (args) = 1;
ASM_INPUT_P (args) = 1;
}
+
return args;
}
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.99
diff -c -p -d -r2.99 gimplify.c
*** gcc/gimplify.c 27 Dec 2004 16:06:13 -0000 2.99
--- gcc/gimplify.c 29 Dec 2004 01:17:34 -0000
*************** gimplify_asm_expr (tree *expr_p, tree *p
*** 3262,3271 ****
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))
{
--- 3262,3267 ----
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.454
diff -c -p -d -r1.454 semantics.c
*** gcc/cp/semantics.c 21 Dec 2004 17:54:24 -0000 1.454
--- gcc/cp/semantics.c 29 Dec 2004 01:17:35 -0000
*************** finish_asm_stmt (int volatile_p, tree st
*** 1139,1200 ****
if (!processing_template_decl)
{
int i;
- int ninputs;
- int noutputs;
! for (t = input_operands; t; t = TREE_CHAIN (t))
{
! tree converted_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)
{
error ("type of asm operand %qE could not be determined",
TREE_VALUE (t));
! converted_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))
{
! /* 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 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);
}
}
--- 1139,1218 ----
if (!processing_template_decl)
{
+ int ninputs, noutputs;
+ const char *constraint;
+ const char **oconstraints;
+ bool allows_mem, allows_reg, is_inout;
+ tree operand;
int i;
! 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)
{
! 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 (operand) == unknown_type_node)
{
error ("type of asm operand %qE could not be determined",
TREE_VALUE (t));
! operand = error_mark_node;
}
! 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 && !cxx_mark_addressable (operand))
! operand = error_mark_node;
}
+ else
+ operand = error_mark_node;
! TREE_VALUE (t) = operand;
}
}