On Fri, Sep 30, 2011 at 1:43 PM, Jan Beulich <jbeul...@suse.com> wrote:
> 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.

I miss documentation for this.  This does not address the other issue
we have, like specifying the set of symbols _defined_ by a toplevel
asm, right?  I might misremember but sth like

extern void foo (void);
asm("" :::: "foo");

was supposed to do the trick.  Or should we treat those as outputs
(given you use inputs for symbol uses)?

Honza, do you remember if we decided on anything here?

Thanks,
Richard.

> gcc/
> 2011-09-30  Jan Beulich  <jbeul...@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  <jbeul...@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
>
>
>

Reply via email to