--- 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
