From patchwork Tue Jul 6 07:39:06 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 57984 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 0709DB6EFE for ; Tue, 6 Jul 2010 17:39:36 +1000 (EST) Received: (qmail 20505 invoked by alias); 6 Jul 2010 07:39:33 -0000 Received: (qmail 20465 invoked by uid 22791); 6 Jul 2010 07:39:26 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, TW_FN, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from vpn.id2.novell.com (HELO vpn.id2.novell.com) (195.33.99.129) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 06 Jul 2010 07:39:13 +0000 Received: from EMEA1-MTA by vpn.id2.novell.com with Novell_GroupWise; Tue, 06 Jul 2010 11:15:14 +0100 Message-Id: <4C32F9BA0200007800009ABF@vpn.id2.novell.com> Date: Tue, 06 Jul 2010 08:39:06 +0100 From: "Jan Beulich" To: Subject: allow certain kinds of inputs to top level asm()-s Mime-Version: 1.0 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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. gcc/ 2010-07-06 Jan Beulich * c-parser.c: New second parameter of c_parser_simple_asm_expr(). Change c_parser_asm_operands()' second parameter's type to 'int'. (c_parser_declaration_or_fndef): Adjust call to c_parser_simple_asm_expr(). (c_parser_asm_definition): Obtain and pass inputs. (c_parser_simple_asm_expr): Adjust simple-asm-expr definition. New second parameter. Handle optional inputs if requested. (c_parser_asm_statement): Adjust calls to c_parser_asm_operands(). (c_parser_asm_statement): Adjust comment. Change second parameter's type to 'int'. Call c_parser_expr_no_commas() instead of c_parser_expression() when 'mode' is negative. * cgraph.c (cgraph_add_asm_node): New parameters 'inputs' and 'loc'. Call check_unique_operand_names(). Initialize new fields of 'node'. * cgraph.h (struct cgraph_asm_node): New members 'inputs' and 'loc'. (cgraph_add_asm_node): New parameters 'inputs' and 'loc'. * cgraphunit.c (cgraph_output_pending_asms): Adjust call to assemble_asm(). (process_function_and_variable_attributes): Process inputs of all asm nodes. (cgraph_output_in_order): Adjust call to assemble_asm(). * lto-cgraph.c (output_cgraph): Call lto_output_toplevel_asms() instead of emitting top level asm-s here. (input_cgraph_1): Call lto_input_toplevel_asms() instead of reading in top level asm-s here. * lto-section-in.c (lto_section_name): Add name for asm-s' section. * lto-streamer-in.c (lto_input_toplevel_asms): New. * lto-streamer-out.c (lto_output_toplevel_asms): New. * lto-streamer.c (lto_get_section_name): Handle LTO_section_asm. * lto-streamer.h (LTO_minor_version): Bump. (enum lto_section_type): Add LTO_section_asm. (struct lto_asm_header): New. (lto_input_toplevel_asms): Declare. (lto_output_toplevel_asms): Declare. * output.h (assemble_asm): New second and third parameter. * stmt.c (check_unique_operand_names): No longer static. * tree.h (check_unique_operand_names): Declare. * varasm.c: Include pretty-print.h. (assemble_asm): New parameters 'inputs' and 'loc'. Handle inputs. gcc/cp/ 2010-07-06 Jan Beulich * parser.c (cp_parser_asm_definition): Correct a comment. Process optional inputs. gcc/testsuite/ 2010-07-06 Jan Beulich * 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. 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. gcc/ 2010-07-06 Jan Beulich * c-parser.c: New second parameter of c_parser_simple_asm_expr(). Change c_parser_asm_operands()' second parameter's type to 'int'. (c_parser_declaration_or_fndef): Adjust call to c_parser_simple_asm_expr(). (c_parser_asm_definition): Obtain and pass inputs. (c_parser_simple_asm_expr): Adjust simple-asm-expr definition. New second parameter. Handle optional inputs if requested. (c_parser_asm_statement): Adjust calls to c_parser_asm_operands(). (c_parser_asm_statement): Adjust comment. Change second parameter's type to 'int'. Call c_parser_expr_no_commas() instead of c_parser_expression() when 'mode' is negative. * cgraph.c (cgraph_add_asm_node): New parameters 'inputs' and 'loc'. Call check_unique_operand_names(). Initialize new fields of 'node'. * cgraph.h (struct cgraph_asm_node): New members 'inputs' and 'loc'. (cgraph_add_asm_node): New parameters 'inputs' and 'loc'. * cgraphunit.c (cgraph_output_pending_asms): Adjust call to assemble_asm(). (process_function_and_variable_attributes): Process inputs of all asm nodes. (cgraph_output_in_order): Adjust call to assemble_asm(). * lto-cgraph.c (output_cgraph): Call lto_output_toplevel_asms() instead of emitting top level asm-s here. (input_cgraph_1): Call lto_input_toplevel_asms() instead of reading in top level asm-s here. * lto-section-in.c (lto_section_name): Add name for asm-s' section. * lto-streamer-in.c (lto_input_toplevel_asms): New. * lto-streamer-out.c (lto_output_toplevel_asms): New. * lto-streamer.c (lto_get_section_name): Handle LTO_section_asm. * lto-streamer.h (LTO_minor_version): Bump. (enum lto_section_type): Add LTO_section_asm. (struct lto_asm_header): New. (lto_input_toplevel_asms): Declare. (lto_output_toplevel_asms): Declare. * output.h (assemble_asm): New second and third parameter. * stmt.c (check_unique_operand_names): No longer static. * tree.h (check_unique_operand_names): Declare. * varasm.c: Include pretty-print.h. (assemble_asm): New parameters 'inputs' and 'loc'. Handle inputs. gcc/cp/ 2010-07-06 Jan Beulich * parser.c (cp_parser_asm_definition): Correct a comment. Process optional inputs. gcc/testsuite/ 2010-07-06 Jan Beulich * 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. --- 2010-06-30/gcc/c-parser.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/c-parser.c 2010-07-02 15:33:45.000000000 +0200 @@ -926,7 +926,7 @@ static struct c_declarator *c_parser_dir static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree); static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, 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 *); @@ -945,7 +945,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 *); @@ -1273,7 +1273,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)) @@ -1406,9 +1406,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 %<;%>"); } @@ -2910,10 +2913,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)); @@ -2927,6 +2931,9 @@ 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 %<)%>")) + *inputsp = c_parser_asm_operands (parser, -1); parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { @@ -4513,10 +4520,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); @@ -4554,9 +4561,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 @@ -4568,7 +4576,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; @@ -4607,9 +4615,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; --- 2010-06-30/gcc/cgraph.c 2010-06-30 08:40:00.000000000 +0200 +++ 2010-06-30/gcc/cgraph.c 2010-07-02 15:33:45.000000000 +0200 @@ -1971,12 +1971,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) --- 2010-06-30/gcc/cgraph.h 2010-06-30 08:40:00.000000000 +0200 +++ 2010-06-30/gcc/cgraph.h 2010-07-02 15:33:45.000000000 +0200 @@ -508,6 +508,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; }; @@ -582,7 +586,7 @@ struct cgraph_node * cgraph_clone_node ( void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); void cgraph_make_edge_direct (struct cgraph_edge *, 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 *); --- 2010-06-30/gcc/cgraphunit.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/cgraphunit.c 2010-07-02 15:33:45.000000000 +0200 @@ -903,7 +903,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; } @@ -964,6 +964,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) { @@ -999,6 +1000,47 @@ process_function_and_variable_attributes varpool_mark_needed_node (vnode); } } + 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 @@ -1810,7 +1852,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: --- 2010-06-30/gcc/cp/parser.c 2010-06-30 08:39:35.000000000 +0200 +++ 2010-06-30/gcc/cp/parser.c 2010-07-02 15:33:45.000000000 +0200 @@ -13537,6 +13537,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. */ @@ -13618,7 +13619,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, @@ -13669,6 +13670,19 @@ 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)) + { + /* Consume the `:'. */ + 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, @@ -13695,7 +13709,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); + } } } --- 2010-06-30/gcc/lto-cgraph.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-cgraph.c 2010-07-02 15:33:45.000000000 +0200 @@ -840,7 +840,6 @@ output_cgraph (cgraph_node_set set, varp int i, n_nodes; lto_cgraph_encoder_t encoder; lto_varpool_encoder_t varpool_encoder; - struct cgraph_asm_node *can; if (flag_wpa) output_cgraph_opt_summary (); @@ -876,19 +875,8 @@ output_cgraph (cgraph_node_set set, varp lto_output_uleb128_stream (ob->main_stream, 0); - /* Emit toplevel asms. */ - for (can = cgraph_asm_nodes; can; can = can->next) - { - int len = TREE_STRING_LENGTH (can->asm_str); - lto_output_uleb128_stream (ob->main_stream, len); - for (i = 0; i < len; ++i) - lto_output_1_stream (ob->main_stream, - TREE_STRING_POINTER (can->asm_str)[i]); - } - - lto_output_uleb128_stream (ob->main_stream, 0); - lto_destroy_simple_output_block (ob); + lto_output_toplevel_asms (); output_varpool (set, vset); output_refs (set, vset, encoder, varpool_encoder); } @@ -1229,7 +1217,6 @@ input_cgraph_1 (struct lto_file_decl_dat VEC(cgraph_node_ptr, heap) *nodes = NULL; struct cgraph_node *node; unsigned i; - unsigned HOST_WIDE_INT len; tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib); while (tag) @@ -1250,18 +1237,7 @@ input_cgraph_1 (struct lto_file_decl_dat tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib); } - /* Input toplevel asms. */ - len = lto_input_uleb128 (ib); - while (len) - { - char *str = (char *)xmalloc (len + 1); - for (i = 0; i < len; ++i) - str[i] = lto_input_1_unsigned (ib); - cgraph_add_asm_node (build_string (len, str)); - free (str); - - len = lto_input_uleb128 (ib); - } + lto_input_toplevel_asms (file_data); for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++) { --- 2010-06-30/gcc/lto-section-in.c 2010-06-08 17:20:08.000000000 +0200 +++ 2010-06-30/gcc/lto-section-in.c 2010-07-02 15:33:45.000000000 +0200 @@ -52,6 +52,7 @@ const char *lto_section_name[LTO_N_SECTI "function_body", "static_initializer", "cgraph", + "asm", "varpool", "refs", "jump_funcs" --- 2010-06-30/gcc/lto-streamer-in.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer-in.c 2010-07-02 15:33:45.000000000 +0200 @@ -2731,6 +2731,52 @@ lto_input_tree (struct lto_input_block * } +/* Input toplevel asms. */ + +void +lto_input_toplevel_asms (struct lto_file_decl_data *file_data) +{ + size_t len; + const char *data = lto_get_section_data (file_data, LTO_section_asm, + NULL, &len); + const struct lto_asm_header *header = (const struct lto_asm_header *) data; + int32_t string_offset; + struct data_in *data_in; + struct lto_input_block ib; + tree str; + + if (! data) + return; + + string_offset = sizeof (*header) + header->main_size; + + LTO_INIT_INPUT_BLOCK (ib, + data + sizeof (*header), + 0, + header->main_size); + + data_in = lto_data_in_create (file_data, data + string_offset, + header->string_size, NULL); + + /* Make sure the file was generated by the exact same compiler. */ + lto_check_version (header->lto_header.major_version, + header->lto_header.minor_version); + + while ((str = input_string_cst (data_in, &ib))) + { + 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); + + lto_free_section_data (file_data, LTO_section_asm, NULL, data, len); +} + + /* Initialization for the LTO reader. */ void --- 2010-06-30/gcc/lto-streamer-out.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer-out.c 2010-07-02 15:33:45.000000000 +0200 @@ -2006,6 +2006,65 @@ output_unreferenced_globals (cgraph_node } +/* Emit toplevel asms. */ + +void +lto_output_toplevel_asms (void) +{ + struct output_block *ob; + struct cgraph_asm_node *can; + char *section_name; + struct lto_output_stream *header_stream; + struct lto_asm_header header; + + if (! cgraph_asm_nodes) + return; + + ob = create_output_block (LTO_section_asm); + + /* Make string 0 be a NULL string. */ + lto_output_1_stream (ob->string_stream, 0); + + for (can = cgraph_asm_nodes; can; can = can->next) + { + output_string_cst (ob, ob->main_stream, can->asm_str); + lto_output_tree (ob, can->inputs, false); + lto_output_location (ob, can->loc); + } + + lto_output_uleb128_stream (ob->main_stream, 0); + + section_name = lto_get_section_name (LTO_section_asm, NULL); + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + /* The entire header stream is computed here. */ + memset (&header, 0, sizeof (struct lto_function_header)); + + /* Write the header. */ + header.lto_header.major_version = LTO_major_version; + header.lto_header.minor_version = LTO_minor_version; + header.lto_header.section_type = LTO_section_asm; + + header.main_size = ob->main_stream->total_size; + header.string_size = ob->string_stream->total_size; + + header_stream = XCNEW (struct lto_output_stream); + lto_output_data_stream (header_stream, &header, sizeof (header)); + lto_write_stream (header_stream); + free (header_stream); + + /* Put all of the gimple and the string table out the asm file as a + block of text. */ + lto_write_stream (ob->main_stream); + lto_write_stream (ob->string_stream); + + lto_end_section (); + + destroy_output_block (ob); +} + + /* Copy the function body of NODE without deserializing. */ static void --- 2010-06-30/gcc/lto-streamer.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer.c 2010-07-02 15:33:45.000000000 +0200 @@ -160,6 +160,9 @@ lto_get_section_name (int section_type, case LTO_section_cgraph: return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL); + case LTO_section_asm: + return concat (LTO_SECTION_NAME_PREFIX, ".asm", NULL); + case LTO_section_varpool: return concat (LTO_SECTION_NAME_PREFIX, ".vars", NULL); --- 2010-06-30/gcc/lto-streamer.h 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer.h 2010-07-02 15:33:45.000000000 +0200 @@ -140,7 +140,7 @@ along with GCC; see the file COPYING3. #define LTO_SECTION_NAME_PREFIX ".gnu.lto_" #define LTO_major_version 1 -#define LTO_minor_version 0 +#define LTO_minor_version 1 typedef unsigned char lto_decl_flags_t; @@ -254,6 +254,7 @@ enum lto_section_type LTO_section_function_body, LTO_section_static_initializer, LTO_section_cgraph, + LTO_section_asm, LTO_section_varpool, LTO_section_refs, LTO_section_jump_functions, @@ -440,6 +441,23 @@ struct lto_decl_header }; +/* Structure describing top level asm()s. */ +struct lto_asm_header +{ + /* The header for all types of sections. */ + struct lto_header lto_header; + + /* Size compressed or 0 if not compressed. */ + int32_t compressed_size; + + /* Size of region for expressions, decls, types, etc. */ + int32_t main_size; + + /* Size of the string table. */ + int32_t string_size; +}; + + /* Statistics gathered during LTO, WPA and LTRANS. */ struct lto_stats_d { @@ -844,6 +862,7 @@ extern void lto_input_function_body (str const char *); extern void lto_input_constructors_and_inits (struct lto_file_decl_data *, const char *); +extern void lto_input_toplevel_asms (struct lto_file_decl_data *); extern void lto_init_reader (void); extern struct data_in *lto_data_in_create (struct lto_file_decl_data *, const char *, unsigned, @@ -856,6 +875,7 @@ extern void lto_register_decl_definition extern struct output_block *create_output_block (enum lto_section_type); extern void destroy_output_block (struct output_block *); extern void lto_output_tree (struct output_block *, tree, bool); +extern void lto_output_toplevel_asms (void); extern void produce_asm (struct output_block *ob, tree fn); --- 2010-06-30/gcc/output.h 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/output.h 2010-07-02 15:33:45.000000000 +0200 @@ -186,7 +186,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. --- 2010-06-30/gcc/stmt.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/stmt.c 2010-07-02 15:33:45.000000000 +0200 @@ -112,7 +112,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); @@ -1227,7 +1226,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; --- 2010-06-30/gcc/testsuite/g++.dg/ext/asm-static-1.C 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/g++.dg/ext/asm-static-1.C 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,21 @@ +/* Check compilation of file scope asm() with input oprand(s). */ +/* { dg-do compile } */ + +extern int a[]; +extern void f(int*); +extern struct s { + int i, a[2]; +} s; +static inline void inl(void) +{ + f(a); +} + +__asm__ (".long %c0" : "i" (f)); +__asm__ (".long %c0" : "i" (a)); +__asm__ (".long %c0" : "i" (inl)); +__asm__ (".long %c0" : "i" (&s.i)); +__asm__ (".long %c0" : "i" (s.a)); +__asm__ (".long %c0, %c1, %c2" : "i" (-1), "i" ((long)f), "i" (a + 1)); +__asm__ (".long %c[arr], %c[cnst], %c[fn]" + : [cnst] "i" (-1), [fn] "i" ((long)f), [arr] "i" (a + 1)); --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-1.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-1.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,21 @@ +/* Check compilation of file scope asm() with input oprand(s). */ +/* { dg-do compile } */ + +extern int a[]; +extern void f(int*); +extern struct s { + int i, a[2]; +} s; +static __inline__ void inl(void) +{ + f(a); +} + +__asm__ (".long %c0" : "i" (f)); +__asm__ (".long %c0" : "i" (a)); +__asm__ (".long %c0" : "i" (inl)); +__asm__ (".long %c0" : "i" (&s.i)); +__asm__ (".long %c0" : "i" (s.a)); +__asm__ (".long %c0, %c1, %c2" : "i" (-1), "i" ((long)f), "i" (a + 1)); +__asm__ (".long %c[arr], %c[cnst], %c[fn]" + : [cnst] "i" (-1), [fn] "i" ((long)f), [arr] "i" (a + 1)); --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-2.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-2.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,8 @@ +/* Check for parse time errors. */ +/* { dg-do compile } */ + +extern int a[]; + +__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" } */ --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-3.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-3.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,7 @@ +/* Check for errors detected before code generation. */ +/* { dg-do compile } */ + +extern int a[]; +extern void f(int*); + +__asm__ (".long %c0" : "i" ((long)a - (long)f)); /* { dg-error "expression not supported" } */ --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-4.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-4.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,8 @@ +/* Check for errors detected during code generation. */ +/* { dg-do compile } */ + +__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" } */ --- 2010-06-30/gcc/tree.h 2010-06-30 13:19:57.000000000 +0200 +++ 2010-06-30/gcc/tree.h 2010-07-02 15:33:45.000000000 +0200 @@ -5258,6 +5258,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 void expand_case (gimple); extern void expand_decl (tree); #ifdef HARD_CONST --- 2010-06-30/gcc/varasm.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/varasm.c 2010-07-02 15:33:45.000000000 +0200 @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. #include "cfglayout.h" #include "basic-block.h" #include "tree-iterator.h" +#include "pretty-print.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -1557,14 +1558,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 --- 2010-06-30/gcc/c-parser.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/c-parser.c 2010-07-02 15:33:45.000000000 +0200 @@ -926,7 +926,7 @@ static struct c_declarator *c_parser_dir static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree); static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, 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 *); @@ -945,7 +945,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 *); @@ -1273,7 +1273,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)) @@ -1406,9 +1406,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 %<;%>"); } @@ -2910,10 +2913,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)); @@ -2927,6 +2931,9 @@ 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 %<)%>")) + *inputsp = c_parser_asm_operands (parser, -1); parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { @@ -4513,10 +4520,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); @@ -4554,9 +4561,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 @@ -4568,7 +4576,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; @@ -4607,9 +4615,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; --- 2010-06-30/gcc/cgraph.c 2010-06-30 08:40:00.000000000 +0200 +++ 2010-06-30/gcc/cgraph.c 2010-07-02 15:33:45.000000000 +0200 @@ -1971,12 +1971,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) --- 2010-06-30/gcc/cgraph.h 2010-06-30 08:40:00.000000000 +0200 +++ 2010-06-30/gcc/cgraph.h 2010-07-02 15:33:45.000000000 +0200 @@ -508,6 +508,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; }; @@ -582,7 +586,7 @@ struct cgraph_node * cgraph_clone_node ( void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); void cgraph_make_edge_direct (struct cgraph_edge *, 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 *); --- 2010-06-30/gcc/cgraphunit.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/cgraphunit.c 2010-07-02 15:33:45.000000000 +0200 @@ -903,7 +903,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; } @@ -964,6 +964,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) { @@ -999,6 +1000,47 @@ process_function_and_variable_attributes varpool_mark_needed_node (vnode); } } + 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 @@ -1810,7 +1852,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: --- 2010-06-30/gcc/cp/parser.c 2010-06-30 08:39:35.000000000 +0200 +++ 2010-06-30/gcc/cp/parser.c 2010-07-02 15:33:45.000000000 +0200 @@ -13537,6 +13537,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. */ @@ -13618,7 +13619,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, @@ -13669,6 +13670,19 @@ 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)) + { + /* Consume the `:'. */ + 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, @@ -13695,7 +13709,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); + } } } --- 2010-06-30/gcc/lto-cgraph.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-cgraph.c 2010-07-02 15:33:45.000000000 +0200 @@ -840,7 +840,6 @@ output_cgraph (cgraph_node_set set, varp int i, n_nodes; lto_cgraph_encoder_t encoder; lto_varpool_encoder_t varpool_encoder; - struct cgraph_asm_node *can; if (flag_wpa) output_cgraph_opt_summary (); @@ -876,19 +875,8 @@ output_cgraph (cgraph_node_set set, varp lto_output_uleb128_stream (ob->main_stream, 0); - /* Emit toplevel asms. */ - for (can = cgraph_asm_nodes; can; can = can->next) - { - int len = TREE_STRING_LENGTH (can->asm_str); - lto_output_uleb128_stream (ob->main_stream, len); - for (i = 0; i < len; ++i) - lto_output_1_stream (ob->main_stream, - TREE_STRING_POINTER (can->asm_str)[i]); - } - - lto_output_uleb128_stream (ob->main_stream, 0); - lto_destroy_simple_output_block (ob); + lto_output_toplevel_asms (); output_varpool (set, vset); output_refs (set, vset, encoder, varpool_encoder); } @@ -1229,7 +1217,6 @@ input_cgraph_1 (struct lto_file_decl_dat VEC(cgraph_node_ptr, heap) *nodes = NULL; struct cgraph_node *node; unsigned i; - unsigned HOST_WIDE_INT len; tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib); while (tag) @@ -1250,18 +1237,7 @@ input_cgraph_1 (struct lto_file_decl_dat tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib); } - /* Input toplevel asms. */ - len = lto_input_uleb128 (ib); - while (len) - { - char *str = (char *)xmalloc (len + 1); - for (i = 0; i < len; ++i) - str[i] = lto_input_1_unsigned (ib); - cgraph_add_asm_node (build_string (len, str)); - free (str); - - len = lto_input_uleb128 (ib); - } + lto_input_toplevel_asms (file_data); for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++) { --- 2010-06-30/gcc/lto-section-in.c 2010-06-08 17:20:08.000000000 +0200 +++ 2010-06-30/gcc/lto-section-in.c 2010-07-02 15:33:45.000000000 +0200 @@ -52,6 +52,7 @@ const char *lto_section_name[LTO_N_SECTI "function_body", "static_initializer", "cgraph", + "asm", "varpool", "refs", "jump_funcs" --- 2010-06-30/gcc/lto-streamer-in.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer-in.c 2010-07-02 15:33:45.000000000 +0200 @@ -2731,6 +2731,52 @@ lto_input_tree (struct lto_input_block * } +/* Input toplevel asms. */ + +void +lto_input_toplevel_asms (struct lto_file_decl_data *file_data) +{ + size_t len; + const char *data = lto_get_section_data (file_data, LTO_section_asm, + NULL, &len); + const struct lto_asm_header *header = (const struct lto_asm_header *) data; + int32_t string_offset; + struct data_in *data_in; + struct lto_input_block ib; + tree str; + + if (! data) + return; + + string_offset = sizeof (*header) + header->main_size; + + LTO_INIT_INPUT_BLOCK (ib, + data + sizeof (*header), + 0, + header->main_size); + + data_in = lto_data_in_create (file_data, data + string_offset, + header->string_size, NULL); + + /* Make sure the file was generated by the exact same compiler. */ + lto_check_version (header->lto_header.major_version, + header->lto_header.minor_version); + + while ((str = input_string_cst (data_in, &ib))) + { + 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); + + lto_free_section_data (file_data, LTO_section_asm, NULL, data, len); +} + + /* Initialization for the LTO reader. */ void --- 2010-06-30/gcc/lto-streamer-out.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer-out.c 2010-07-02 15:33:45.000000000 +0200 @@ -2006,6 +2006,65 @@ output_unreferenced_globals (cgraph_node } +/* Emit toplevel asms. */ + +void +lto_output_toplevel_asms (void) +{ + struct output_block *ob; + struct cgraph_asm_node *can; + char *section_name; + struct lto_output_stream *header_stream; + struct lto_asm_header header; + + if (! cgraph_asm_nodes) + return; + + ob = create_output_block (LTO_section_asm); + + /* Make string 0 be a NULL string. */ + lto_output_1_stream (ob->string_stream, 0); + + for (can = cgraph_asm_nodes; can; can = can->next) + { + output_string_cst (ob, ob->main_stream, can->asm_str); + lto_output_tree (ob, can->inputs, false); + lto_output_location (ob, can->loc); + } + + lto_output_uleb128_stream (ob->main_stream, 0); + + section_name = lto_get_section_name (LTO_section_asm, NULL); + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + /* The entire header stream is computed here. */ + memset (&header, 0, sizeof (struct lto_function_header)); + + /* Write the header. */ + header.lto_header.major_version = LTO_major_version; + header.lto_header.minor_version = LTO_minor_version; + header.lto_header.section_type = LTO_section_asm; + + header.main_size = ob->main_stream->total_size; + header.string_size = ob->string_stream->total_size; + + header_stream = XCNEW (struct lto_output_stream); + lto_output_data_stream (header_stream, &header, sizeof (header)); + lto_write_stream (header_stream); + free (header_stream); + + /* Put all of the gimple and the string table out the asm file as a + block of text. */ + lto_write_stream (ob->main_stream); + lto_write_stream (ob->string_stream); + + lto_end_section (); + + destroy_output_block (ob); +} + + /* Copy the function body of NODE without deserializing. */ static void --- 2010-06-30/gcc/lto-streamer.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer.c 2010-07-02 15:33:45.000000000 +0200 @@ -160,6 +160,9 @@ lto_get_section_name (int section_type, case LTO_section_cgraph: return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL); + case LTO_section_asm: + return concat (LTO_SECTION_NAME_PREFIX, ".asm", NULL); + case LTO_section_varpool: return concat (LTO_SECTION_NAME_PREFIX, ".vars", NULL); --- 2010-06-30/gcc/lto-streamer.h 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/lto-streamer.h 2010-07-02 15:33:45.000000000 +0200 @@ -140,7 +140,7 @@ along with GCC; see the file COPYING3. #define LTO_SECTION_NAME_PREFIX ".gnu.lto_" #define LTO_major_version 1 -#define LTO_minor_version 0 +#define LTO_minor_version 1 typedef unsigned char lto_decl_flags_t; @@ -254,6 +254,7 @@ enum lto_section_type LTO_section_function_body, LTO_section_static_initializer, LTO_section_cgraph, + LTO_section_asm, LTO_section_varpool, LTO_section_refs, LTO_section_jump_functions, @@ -440,6 +441,23 @@ struct lto_decl_header }; +/* Structure describing top level asm()s. */ +struct lto_asm_header +{ + /* The header for all types of sections. */ + struct lto_header lto_header; + + /* Size compressed or 0 if not compressed. */ + int32_t compressed_size; + + /* Size of region for expressions, decls, types, etc. */ + int32_t main_size; + + /* Size of the string table. */ + int32_t string_size; +}; + + /* Statistics gathered during LTO, WPA and LTRANS. */ struct lto_stats_d { @@ -844,6 +862,7 @@ extern void lto_input_function_body (str const char *); extern void lto_input_constructors_and_inits (struct lto_file_decl_data *, const char *); +extern void lto_input_toplevel_asms (struct lto_file_decl_data *); extern void lto_init_reader (void); extern struct data_in *lto_data_in_create (struct lto_file_decl_data *, const char *, unsigned, @@ -856,6 +875,7 @@ extern void lto_register_decl_definition extern struct output_block *create_output_block (enum lto_section_type); extern void destroy_output_block (struct output_block *); extern void lto_output_tree (struct output_block *, tree, bool); +extern void lto_output_toplevel_asms (void); extern void produce_asm (struct output_block *ob, tree fn); --- 2010-06-30/gcc/output.h 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/output.h 2010-07-02 15:33:45.000000000 +0200 @@ -186,7 +186,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. --- 2010-06-30/gcc/stmt.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/stmt.c 2010-07-02 15:33:45.000000000 +0200 @@ -112,7 +112,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); @@ -1227,7 +1226,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; --- 2010-06-30/gcc/testsuite/g++.dg/ext/asm-static-1.C 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/g++.dg/ext/asm-static-1.C 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,21 @@ +/* Check compilation of file scope asm() with input oprand(s). */ +/* { dg-do compile } */ + +extern int a[]; +extern void f(int*); +extern struct s { + int i, a[2]; +} s; +static inline void inl(void) +{ + f(a); +} + +__asm__ (".long %c0" : "i" (f)); +__asm__ (".long %c0" : "i" (a)); +__asm__ (".long %c0" : "i" (inl)); +__asm__ (".long %c0" : "i" (&s.i)); +__asm__ (".long %c0" : "i" (s.a)); +__asm__ (".long %c0, %c1, %c2" : "i" (-1), "i" ((long)f), "i" (a + 1)); +__asm__ (".long %c[arr], %c[cnst], %c[fn]" + : [cnst] "i" (-1), [fn] "i" ((long)f), [arr] "i" (a + 1)); --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-1.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-1.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,21 @@ +/* Check compilation of file scope asm() with input oprand(s). */ +/* { dg-do compile } */ + +extern int a[]; +extern void f(int*); +extern struct s { + int i, a[2]; +} s; +static __inline__ void inl(void) +{ + f(a); +} + +__asm__ (".long %c0" : "i" (f)); +__asm__ (".long %c0" : "i" (a)); +__asm__ (".long %c0" : "i" (inl)); +__asm__ (".long %c0" : "i" (&s.i)); +__asm__ (".long %c0" : "i" (s.a)); +__asm__ (".long %c0, %c1, %c2" : "i" (-1), "i" ((long)f), "i" (a + 1)); +__asm__ (".long %c[arr], %c[cnst], %c[fn]" + : [cnst] "i" (-1), [fn] "i" ((long)f), [arr] "i" (a + 1)); --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-2.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-2.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,8 @@ +/* Check for parse time errors. */ +/* { dg-do compile } */ + +extern int a[]; + +__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" } */ --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-3.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-3.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,7 @@ +/* Check for errors detected before code generation. */ +/* { dg-do compile } */ + +extern int a[]; +extern void f(int*); + +__asm__ (".long %c0" : "i" ((long)a - (long)f)); /* { dg-error "expression not supported" } */ --- 2010-06-30/gcc/testsuite/gcc.dg/asm-static-4.c 1970-01-01 01:00:00.000000000 +0100 +++ 2010-06-30/gcc/testsuite/gcc.dg/asm-static-4.c 2010-07-02 15:33:45.000000000 +0200 @@ -0,0 +1,8 @@ +/* Check for errors detected during code generation. */ +/* { dg-do compile } */ + +__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" } */ --- 2010-06-30/gcc/tree.h 2010-06-30 13:19:57.000000000 +0200 +++ 2010-06-30/gcc/tree.h 2010-07-02 15:33:45.000000000 +0200 @@ -5258,6 +5258,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 void expand_case (gimple); extern void expand_decl (tree); #ifdef HARD_CONST --- 2010-06-30/gcc/varasm.c 2010-06-30 08:40:05.000000000 +0200 +++ 2010-06-30/gcc/varasm.c 2010-07-02 15:33:45.000000000 +0200 @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. #include "cfglayout.h" #include "basic-block.h" #include "tree-iterator.h" +#include "pretty-print.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -1557,14 +1558,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