diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7b44126c745081c4c6da1ab827bae1b61f7c875a..d89c8923645436f2fad9631ac0079217a416b0b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +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 diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index d2963b374545bcce6e4ace76b67b38330cf936d3..5eae3aa7d5ec5edca018333d3b94488ff8623c9d 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -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; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 622a0012a13ba1fdd9a2688084c8dac0608c2ba5..9e96120e8083bdea8c3ffc0ae699eb1832741ab3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +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 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ab1c028ff5d53885d82f2f0fe49f5ba674bf94cf..b34de199adb045bf66f99983bf79fbd229d2644a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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; } } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f89b7207c14836ff69d4e7757ec81e12fd4b8ad3..ca3759769b133331ef42cefa728e2495df7f7a98 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -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)) { diff --git a/gcc/testsuite/g++.dg/opt/asm2.C b/gcc/testsuite/g++.dg/opt/asm2.C new file mode 100644 index 0000000000000000000000000000000000000000..4e3244169c779d9d83b42779251dddbfcd392274 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/asm2.C @@ -0,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)); +} diff --git a/gcc/testsuite/gcc.dg/asm-9.c b/gcc/testsuite/gcc.dg/asm-9.c new file mode 100644 index 0000000000000000000000000000000000000000..4e3244169c779d9d83b42779251dddbfcd392274 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asm-9.c @@ -0,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)); +}