This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 2/2] allow certain kinds of inputs to top level asm()-s
- From: "Jan Beulich" <JBeulich at suse dot com>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 30 Sep 2011 12:43:54 +0100
- Subject: [PATCH 2/2] allow certain kinds of inputs to top level asm()-s
This is so that use of symbols referenced in these asm()-s can be
properly tracked by the compiler, just like is the case for all other
asm()-s. I'm particularly looking forward to use this in the Linux
kernel. It is certainly not very useful in PIC code, at least not with
some extra care.
gcc/
2011-09-30 Jan Beulich <jbeulich@suse.com>
* c-parser.c (c_parser_simple_asm_expr): Add new second parameter
'inputsp'. Process inputs if caller indicates they are allowed. Adjust
calls to c_parser_asm_operands().
(c_parser_asm_operands): Change type of second parameter from 'bool'
to 'int'. Call c_parser_expression() only for non-negative 'mode', and
c_parser_expr_no_commas() otherwise.
(c_parser_declaration_or_fndef): Pass NULL as new second argument to
c_parser_simple_asm_expr().
(c_parser_asm_definition): New local variables 'loc' and 'inputs'.
Adjust calls to c_parser_simple_asm_expr() and cgraph_add_asm_node().
(c_parser_simple_asm_expr):
* cgraph.c (cgraph_add_asm_node): Call check_unique_operand_names() to
validate input operands. Store inputs and location.
* cgraph.h (struct cgraph_asm_node): Add 'inputs' and 'loc'.
(cgraph_add_asm_node): New second and third parameters.
* cgraphunit.c (cgraph_output_pending_asms): Pass new second and third
arguments to assemble_asm().
(process_function_and_variable_attributes): New local variable 'anode'.
Process list starting from 'cgraph_asm_nodes'.
(cgraph_output_in_order): Pass new second and third arguments to
assemble_asm().
* cp/parser.c (enum required_token): Add RT_COLON_NO_OUTPUT.
(cp_parser_asm_definition): New local variable 'loc'. Correct a
comment. Parse and process input operands if permitted.
(cp_parser_required_error): Handle new case RT_COLON_NO_OUTPUT.
* lto-streamer-in.c (lto_input_toplevel_asms): Pass new second and
third arguments to cgraph_add_asm_node().
* lto-streamer-out.c (lto_output_toplevel_asms): Also output inputs
and location.
* output.h (assemble_asm): New second and third parameters.
* stmt.c (check_unique_operand_names): Remove static declaration and
make global.
* tree.h (check_unique_operand_names): Declare.
* varasm.c: Include pretty-print.h.
(assemble_asm): New parameters 'inputs' and 'loc'. Process inputs if
provided.
gcc/testsuite/
2011-09-30 Jan Beulich <jbeulich@suse.com>
* g++.dg/ext/asm-static-1.C: New.
* gcc.dg/asm-static-1.c: New.
* gcc.dg/asm-static-2.c: New.
* gcc.dg/asm-static-3.c: New.
* gcc.dg/asm-static-4.c: New.
--- 2011-09-29.orig/gcc/c-parser.c 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/c-parser.c 2011-09-29 15:07:29.000000000 +0200
@@ -1131,7 +1131,7 @@ static struct c_arg_info *c_parser_parms
static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree,
tree);
static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
-static tree c_parser_simple_asm_expr (c_parser *);
+static tree c_parser_simple_asm_expr (c_parser *, tree *);
static tree c_parser_attributes (c_parser *);
static struct c_type_name *c_parser_type_name (c_parser *);
static struct c_expr c_parser_initializer (c_parser *);
@@ -1150,7 +1150,7 @@ static void c_parser_while_statement (c_
static void c_parser_do_statement (c_parser *);
static void c_parser_for_statement (c_parser *);
static tree c_parser_asm_statement (c_parser *);
-static tree c_parser_asm_operands (c_parser *, bool);
+static tree c_parser_asm_operands (c_parser *, int);
static tree c_parser_asm_goto_operands (c_parser *);
static tree c_parser_asm_clobbers (c_parser *);
static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
@@ -1623,7 +1623,7 @@ c_parser_declaration_or_fndef (c_parser
function definition. */
fndef_ok = false;
if (c_parser_next_token_is_keyword (parser, RID_ASM))
- asm_name = c_parser_simple_asm_expr (parser);
+ asm_name = c_parser_simple_asm_expr (parser, NULL);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
postfix_attrs = c_parser_attributes (parser);
if (c_parser_next_token_is (parser, CPP_EQ))
@@ -1782,9 +1782,12 @@ c_parser_declaration_or_fndef (c_parser
static void
c_parser_asm_definition (c_parser *parser)
{
- tree asm_str = c_parser_simple_asm_expr (parser);
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree inputs = NULL_TREE;
+ tree asm_str = c_parser_simple_asm_expr (parser, &inputs);
+
if (asm_str)
- cgraph_add_asm_node (asm_str);
+ cgraph_add_asm_node (asm_str, inputs, loc);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
@@ -3330,10 +3333,11 @@ c_parser_asm_string_literal (c_parser *p
simple-asm-expr:
asm ( asm-string-literal )
+ asm ( asm-string-literal :: asm-operands )
*/
static tree
-c_parser_simple_asm_expr (c_parser *parser)
+c_parser_simple_asm_expr (c_parser *parser, tree *inputsp)
{
tree str;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
@@ -3347,6 +3351,11 @@ c_parser_simple_asm_expr (c_parser *pars
return NULL_TREE;
}
str = c_parser_asm_string_literal (parser);
+ if (inputsp && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)
+ && c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")
+ && c_parser_require (parser, CPP_COLON,
+ "expected %<:%> (no output operands allowed here)"))
+ *inputsp = c_parser_asm_operands (parser, -1);
parser->lex_untranslated_string = false;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
{
@@ -5050,10 +5059,10 @@ c_parser_asm_statement (c_parser *parser
/* For asm goto, we don't allow output operands, but reserve
the slot for a future extension that does allow them. */
if (!is_goto)
- outputs = c_parser_asm_operands (parser, false);
+ outputs = c_parser_asm_operands (parser, 0);
break;
case 1:
- inputs = c_parser_asm_operands (parser, true);
+ inputs = c_parser_asm_operands (parser, 1);
break;
case 2:
clobbers = c_parser_asm_clobbers (parser);
@@ -5091,9 +5100,10 @@ c_parser_asm_statement (c_parser *parser
goto error;
}
-/* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but
- not outputs), apply the default conversion of functions and arrays
- to pointers.
+/* Parse asm operands, a GNU extension. If MODE is non-zero (for inputs
+ but not outputs), apply the default conversion of functions and arrays
+ to pointers. If MODE is negative (for inputs of asm definitions),
+ don't allow comma expressions.
asm-operands:
asm-operand
@@ -5105,7 +5115,7 @@ c_parser_asm_statement (c_parser *parser
*/
static tree
-c_parser_asm_operands (c_parser *parser, bool convert_p)
+c_parser_asm_operands (c_parser *parser, int mode)
{
tree list = NULL_TREE;
location_t loc;
@@ -5144,9 +5154,12 @@ c_parser_asm_operands (c_parser *parser,
return NULL_TREE;
}
loc = c_parser_peek_token (parser)->location;
- expr = c_parser_expression (parser);
+ if (mode >= 0)
+ expr = c_parser_expression (parser);
+ else
+ expr = c_parser_expr_no_commas(parser, NULL);
mark_exp_read (expr.value);
- if (convert_p)
+ if (mode)
expr = default_function_array_conversion (loc, expr);
expr.value = c_fully_fold (expr.value, false, NULL);
parser->lex_untranslated_string = true;
--- 2011-09-29.orig/gcc/cgraph.c 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/cgraph.c 2011-09-29 15:07:29.000000000 +0200
@@ -1990,12 +1990,15 @@ change_decl_assembler_name (tree decl, t
/* Add a top-level asm statement to the list. */
struct cgraph_asm_node *
-cgraph_add_asm_node (tree asm_str)
+cgraph_add_asm_node (tree asm_str, tree inputs, location_t loc)
{
struct cgraph_asm_node *node;
node = ggc_alloc_cleared_cgraph_asm_node ();
node->asm_str = asm_str;
+ node->inputs = check_unique_operand_names (NULL_TREE, inputs, NULL_TREE)
+ ? inputs : NULL_TREE;
+ node->loc = loc;
node->order = cgraph_order++;
node->next = NULL;
if (cgraph_asm_nodes == NULL)
--- 2011-09-29.orig/gcc/cgraph.h 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/cgraph.h 2011-09-29 15:07:29.000000000 +0200
@@ -430,6 +430,10 @@ struct GTY(()) cgraph_asm_node {
struct cgraph_asm_node *next;
/* String for this asm node. */
tree asm_str;
+ /* Inputs for this asm node (optional). */
+ tree inputs;
+ /* Source location of the asm(). */
+ location_t loc;
/* Ordering of all cgraph nodes. */
int order;
};
@@ -510,7 +514,7 @@ void cgraph_redirect_edge_callee (struct
void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *);
bool cgraph_only_called_directly_p (struct cgraph_node *);
-struct cgraph_asm_node *cgraph_add_asm_node (tree);
+struct cgraph_asm_node *cgraph_add_asm_node (tree, tree, location_t);
bool cgraph_function_possibly_inlined_p (tree);
void cgraph_unnest_node (struct cgraph_node *);
--- 2011-09-29.orig/gcc/cgraphunit.c 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/cgraphunit.c 2011-09-29 15:07:29.000000000 +0200
@@ -819,7 +819,7 @@ cgraph_output_pending_asms (void)
return;
for (can = cgraph_asm_nodes; can; can = can->next)
- assemble_asm (can->asm_str);
+ assemble_asm (can->asm_str, can->inputs, can->loc);
cgraph_asm_nodes = NULL;
}
@@ -972,6 +972,7 @@ process_function_and_variable_attributes
{
struct cgraph_node *node;
struct varpool_node *vnode;
+ struct cgraph_asm_node *anode;
for (node = cgraph_nodes; node != first; node = node->next)
{
@@ -1052,6 +1053,47 @@ process_function_and_variable_attributes
}
process_common_attributes (decl);
}
+ for (anode = cgraph_asm_nodes; anode; anode = anode->next)
+ if (anode->inputs)
+ {
+ tree node = anode->inputs;
+
+ for (; node && node != error_mark_node; node = TREE_CHAIN (node))
+ {
+ tree value = TREE_VALUE (node);
+
+ while (value && value != error_mark_node)
+ {
+ switch (TREE_CODE (value))
+ {
+ case INTEGER_CST:
+ value = NULL_TREE;
+ break;
+
+ CASE_CONVERT:
+ case ADDR_EXPR:
+ case FDESC_EXPR:
+ case POINTER_PLUS_EXPR:
+ case COMPONENT_REF:
+ value = TREE_OPERAND (value, 0);
+ break;
+
+ case FUNCTION_DECL:
+ case VAR_DECL:
+ mark_decl_referenced (value);
+ value = NULL_TREE;
+ break;
+
+ default:
+ error_at (EXPR_LOCATION (value),
+ "expression not supported as file scope"
+ " asm() input");
+ value = NULL_TREE;
+ break;
+ }
+ }
+ }
+ }
}
/* Process CGRAPH_NODES_NEEDED queue, analyze each function (and transitively
@@ -1965,7 +2007,8 @@ cgraph_output_in_order (void)
break;
case ORDER_ASM:
- assemble_asm (nodes[i].u.a->asm_str);
+ assemble_asm (nodes[i].u.a->asm_str, nodes[i].u.a->inputs,
+ nodes[i].u.a->loc);
break;
case ORDER_UNDEFINED:
--- 2011-09-29.orig/gcc/cp/parser.c 2011-09-28 10:53:33.000000000 +0200
+++ 2011-09-29/gcc/cp/parser.c 2011-09-29 15:07:29.000000000 +0200
@@ -139,6 +139,7 @@ typedef enum required_token {
RT_MULT, /* '*' */
RT_COMPL, /* '~' */
RT_COLON, /* ':' */
+ RT_COLON_NO_OUTPUT, /* ':' with "no output" remark */
RT_COLON_SCOPE, /* ':' or '::' */
RT_CLOSE_PAREN, /* ')' */
RT_COMMA_CLOSE_PAREN, /* ',' or ')' */
@@ -14282,6 +14283,7 @@ cp_parser_asm_definition (cp_parser* par
bool invalid_inputs_p = false;
bool invalid_outputs_p = false;
bool goto_p = false;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
required_token missing = RT_NONE;
/* Look for the `asm' keyword. */
@@ -14363,7 +14365,7 @@ cp_parser_asm_definition (cp_parser* par
{
/* Consume the `:' or `::'. */
cp_lexer_consume_token (parser->lexer);
- /* Parse the output-operands. */
+ /* Parse the input-operands. */
if (cp_lexer_next_token_is_not (parser->lexer,
CPP_COLON)
&& cp_lexer_next_token_is_not (parser->lexer,
@@ -14414,6 +14416,34 @@ cp_parser_asm_definition (cp_parser* par
}
else if (goto_p)
missing = RT_COLON_SCOPE;
+ else if (cp_parser_allow_gnu_extensions_p (parser)
+ && ! parser->in_function_body
+ && (cp_lexer_next_token_is (parser->lexer, CPP_COLON)
+ || cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)))
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ /* Consume the `:'. */
+ cp_lexer_consume_token (parser->lexer);
+ if (! cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ invalid_outputs_p = true;
+ missing = RT_COLON_NO_OUTPUT;
+ }
+ }
+
+ if (! invalid_outputs_p)
+ {
+ /* Consume the `:' or `::'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Parse the input-operands. */
+ inputs = cp_parser_asm_operand_list (parser);
+
+ if (inputs == error_mark_node)
+ invalid_inputs_p = true;
+ }
+ }
/* Look for the closing `)'. */
if (!cp_parser_require (parser, missing ? CPP_COLON : CPP_CLOSE_PAREN,
@@ -14440,7 +14470,33 @@ cp_parser_asm_definition (cp_parser* par
}
}
else
- cgraph_add_asm_node (string);
+ {
+ tree input = inputs;
+
+ while (input && input != error_mark_node)
+ {
+ tree operand = decay_conversion (TREE_VALUE (input));
+
+ /* 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 (input));
+ operand = error_mark_node;
+ }
+
+ if (!cxx_mark_addressable (operand))
+ operand = error_mark_node;
+
+ TREE_VALUE (input) = operand;
+
+ input = TREE_CHAIN (input);
+ }
+ cgraph_add_asm_node (string, inputs, loc);
+ }
}
}
@@ -21344,6 +21400,9 @@ cp_parser_required_error (cp_parser *par
case RT_COLON:
cp_parser_error (parser, "expected %<:%>");
return;
+ case RT_COLON_NO_OUTPUT:
+ cp_parser_error (parser, "expected %<:%> (no output operands allowed here)");
+ return;
case RT_COLON_SCOPE:
cp_parser_error (parser, "expected %<:%> or %<::%>");
return;
--- 2011-09-29.orig/gcc/lto-streamer-in.c 2011-09-29 15:07:23.000000000 +0200
+++ 2011-09-29/gcc/lto-streamer-in.c 2011-09-29 15:07:29.000000000 +0200
@@ -1173,7 +1173,12 @@ lto_input_toplevel_asms (struct lto_file
header->lto_header.minor_version);
while ((str = streamer_read_string_cst (data_in, &ib)))
- cgraph_add_asm_node (str);
+ {
+ tree inputs = lto_input_tree (&ib, data_in);
+ location_t loc = lto_input_location (&ib, data_in);
+
+ cgraph_add_asm_node (str, inputs, loc);
+ }
clear_line_info (data_in);
lto_data_in_delete (data_in);
--- 2011-09-29.orig/gcc/lto-streamer-out.c 2011-09-29 15:07:23.000000000 +0200
+++ 2011-09-29/gcc/lto-streamer-out.c 2011-09-29 15:07:29.000000000 +0200
@@ -954,7 +954,11 @@ lto_output_toplevel_asms (void)
streamer_write_char_stream (ob->string_stream, 0);
for (can = cgraph_asm_nodes; can; can = can->next)
- streamer_write_string_cst (ob, ob->main_stream, can->asm_str);
+ {
+ streamer_write_string_cst (ob, ob->main_stream, can->asm_str);
+ lto_output_tree (ob, can->inputs, false);
+ lto_output_location (ob, can->loc);
+ }
streamer_write_string_cst (ob, ob->main_stream, NULL_TREE);
--- 2011-09-29.orig/gcc/output.h 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/output.h 2011-09-29 15:07:29.000000000 +0200
@@ -188,7 +188,7 @@ extern void default_assemble_visibility
/* Output a string of literal assembler code
for an `asm' keyword used between functions. */
-extern void assemble_asm (tree);
+extern void assemble_asm (tree, tree, location_t);
/* Output assembler code for the constant pool of a function and associated
with defining the name of the function. DECL describes the function.
--- 2011-09-29.orig/gcc/stmt.c 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/stmt.c 2011-09-29 15:07:29.000000000 +0200
@@ -113,7 +113,6 @@ static int n_occurrences (int, const cha
static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *);
static void expand_nl_goto_receiver (void);
static bool check_operand_nalternatives (tree, tree);
-static bool check_unique_operand_names (tree, tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree, tree);
static void expand_null_return_1 (void);
static void expand_value_return (rtx);
@@ -1250,7 +1249,7 @@ check_operand_nalternatives (tree output
are identifiers, and so have been canonicalized by get_identifier,
so all we need are pointer comparisons. */
-static bool
+bool
check_unique_operand_names (tree outputs, tree inputs, tree labels)
{
tree i, j;
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/g++.dg/ext/asm-static-1.C 2011-09-29 15:07:29.000000000 +0200
@@ -0,0 +1,26 @@
+/* Check compilation of file scope asm() with input oprand(s). */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+extern int aaa[];
+extern void fff(int*);
+extern struct s {
+ int i, a[2];
+} sss;
+static inline void iii(void)
+{
+}
+
+__asm__ (".long %c0" : : "i" (fff));
+__asm__ (".long %c0" : : "i" (aaa));
+__asm__ (".long %c0" : : "i" (iii));
+__asm__ (".long %c0" : : "i" (&sss.i));
+__asm__ (".long %c0" : : "i" (sss.a));
+__asm__ (".long %c0, %c1, %c2" :: "i" (-1), "i" ((long)fff), "i" (aaa + 1));
+__asm__ (".long %c[arr], %c[cnst], %c[fn]"
+ :: [cnst] "i" (-1), [fn] "i" ((long)fff), [arr] "i" (aaa + 1));
+
+/* { dg-final { scan-assembler "long.*aaa" } } */
+/* { dg-final { scan-assembler "long.*fff" } } */
+/* { dg-final { scan-assembler "long.*iii" } } */
+/* { dg-final { scan-assembler "long.*sss" } } */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-1.c 2011-09-29 15:07:29.000000000 +0200
@@ -0,0 +1,26 @@
+/* Check compilation of file scope asm() with input oprand(s). */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+extern int aaa[];
+extern void fff(int*);
+extern struct s {
+ int i, a[2];
+} sss;
+static __inline__ void iii(void)
+{
+}
+
+__asm__ (".long %c0" :: "i" (fff));
+__asm__ (".long %c0" :: "i" (aaa));
+__asm__ (".long %c0" :: "i" (iii));
+__asm__ (".long %c0" :: "i" (&sss.i));
+__asm__ (".long %c0" :: "i" (sss.a));
+__asm__ (".long %c0, %c1, %c2" :: "i" (-1), "i" ((long)fff), "i" (aaa + 1));
+__asm__ (".long %c[arr], %c[cnst], %c[fn]"
+ :: [cnst] "i" (-1), [fn] "i" ((long)fff), [arr] "i" (aaa + 1));
+
+/* { dg-final { scan-assembler "long.*aaa" } } */
+/* { dg-final { scan-assembler "long.*fff" } } */
+/* { dg-final { scan-assembler "long.*iii" } } */
+/* { dg-final { scan-assembler "long.*sss" } } */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-2.c 2011-09-29 15:07:29.000000000 +0200
@@ -0,0 +1,9 @@
+/* Check for parse time errors. */
+/* { dg-do compile } */
+
+extern int a[];
+
+__asm__ (".long %c0" : "i" (0)); /* { dg-error "expected .?:.*no output operand" } */
+__asm__ (".long %c0" ::: "i" (0)); /* { dg-error "expected string literal" } */
+__asm__ (".long %c0" :: "=g" (a[0]): "0" (0)); /* { dg-error "expected .?\\)" } */
+__asm__ (".long %c[n]" :: [n] "i" (0), [n] "i" (0)); /* { dg-error "duplicate.*operand name" } */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-3.c 2011-09-29 15:07:29.000000000 +0200
@@ -0,0 +1,8 @@
+/* Check for errors detected before code generation. */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+extern int a[];
+extern void f(int*);
+
+__asm__ (".long %c0" :: "i" ((long)a - (long)f)); /* { dg-error "expression not supported" } */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-4.c 2011-09-29 15:07:29.000000000 +0200
@@ -0,0 +1,9 @@
+/* Check for errors detected during code generation. */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+__asm__ (".long %0" :: "r" (0)); /* { dg-warning "invalid.*constraint ignored" } */
+__asm__ (".long %c1" :: "i" (0)); /* { dg-error "operand number out of range" } */
+__asm__ (".long %!0" :: "i" (0)); /* { dg-error "invalid.*%-code" } */
+__asm__ (".long %c[n" :: "i" (0)); /* { dg-error "missing close brace" } */
+__asm__ (".long %c[n]" :: "i" (0)); /* { dg-error "undefined named.*operand" } */
--- 2011-09-29.orig/gcc/tree.h 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/tree.h 2011-09-29 15:07:29.000000000 +0200
@@ -5624,6 +5624,7 @@ extern bool parse_input_constraint (cons
const char * const *, bool *, bool *);
extern void expand_asm_stmt (gimple);
extern tree resolve_asm_operand_names (tree, tree, tree, tree);
+extern bool check_unique_operand_names (tree, tree, tree);
extern bool expand_switch_using_bit_tests_p (tree, tree, unsigned int,
unsigned int);
extern void expand_case (gimple);
--- 2011-09-29.orig/gcc/varasm.c 2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/varasm.c 2011-09-29 15:07:29.000000000 +0200
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.
#include "basic-block.h"
#include "tree-iterator.h"
#include "pointer-set.h"
+#include "pretty-print.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
@@ -1352,14 +1353,111 @@ make_decl_rtl_for_debug (tree decl)
for an `asm' keyword used between functions. */
void
-assemble_asm (tree string)
+assemble_asm (tree string, tree inputs, location_t loc)
{
app_enable ();
if (TREE_CODE (string) == ADDR_EXPR)
string = TREE_OPERAND (string, 0);
- fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
+ if (inputs)
+ {
+ const char *p = TREE_STRING_POINTER (string);
+ char c;
+
+ putc ('\t', asm_out_file);
+
+ while ((c = *p++))
+ {
+ tree node;
+
+ if (c != '%')
+ {
+ putc (c, asm_out_file);
+ continue;
+ }
+
+ c = *p;
+ if (!ISDIGIT(c))
+ switch (c)
+ {
+ case 'c': case 'a':
+ /* For now simply ignore (but also don't require) these. */
+ c = *++p;
+ break;
+ case '%':
+ ++p;
+ putc ('%', asm_out_file);
+ continue;
+ }
+ if (c == '[')
+ {
+ const char *end = strchr (++p, ']');
+ char *q;
+
+ if (! end)
+ {
+ error_at (loc,
+ "missing close brace for named asm() operand");
+ break;
+ }
+ q = xstrndup (p, end - p);
+
+ for (node = inputs; node && node != error_mark_node; )
+ {
+ tree name = TREE_PURPOSE (TREE_PURPOSE (node));
+
+ if (name && ! strcmp (TREE_STRING_POINTER (name), q))
+ break;
+ node = TREE_CHAIN (node);
+ }
+ if (! node)
+ error_at (loc, "undefined named asm() operand %qs",
+ identifier_to_locale (q));
+ free (q);
+ p = end + 1;
+ }
+ else if (ISDIGIT(c))
+ {
+ char *endp;
+ unsigned long opnum = strtoul (p, &endp, 10);
+
+ for (node = inputs; opnum-- && node && node != error_mark_node; )
+ node = TREE_CHAIN (node);
+
+ if (! node)
+ error_at (loc, "asm() operand number out of range");
+ p = endp;
+ }
+ else
+ {
+ error_at (loc,
+ "unsupported or invalid asm() %%-code"
+ " in this context");
+ break;
+ }
+
+ if (node && node != error_mark_node)
+ {
+ tree val = TREE_VALUE (node);
+
+ string = TREE_VALUE (TREE_PURPOSE (node));
+ gcc_assert (TREE_CODE (string) == STRING_CST);
+ if (strcmp (TREE_STRING_POINTER (string), "i"))
+ warning_at (loc, 0,
+ "unsupported or invalid asm() constraint"
+ " ignored - \"i\" assumed");
+
+ output_addr_const (asm_out_file,
+ expand_expr (val, NULL_RTX, VOIDmode,
+ EXPAND_INITIALIZER));
+ }
+ }
+
+ putc ('\n', asm_out_file);
+ }
+ else
+ fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
}
/* Record an element in the table of global destructors. SYMBOL is