This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]