}
if (cxx_dialect >= cxx11)
- cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__");
+ {
+ cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__");
+ cpp_define (pfile, "__GXX_CONSTEXPR_ASM__");
+ }
/* Binary literals have been allowed in g++ before C++11
and were standardized for C++14. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
}
+/* Parse a string literal or constant expression yielding a string.
+ The constant expression uses extra parens to avoid ambiguity with "x" (expr).
+
+ asm-string-expr:
+ string-literal
+ ( constant-expr ) */
+
+static tree
+cp_parser_asm_string_expression (cp_parser *parser)
+{
+ cp_token *tok = cp_lexer_peek_token (parser->lexer);
+
+ if (tok->type == CPP_OPEN_PAREN)
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+ tree string = cp_parser_constant_expression (parser);
+ if (string != error_mark_node)
+ string = cxx_constant_value (string, tf_error);
+ if (TREE_CODE (string) == NOP_EXPR)
+ string = TREE_OPERAND (string, 0);
+ if (TREE_CODE (string) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (string, 0)) == STRING_CST)
+ string = TREE_OPERAND (string, 0);
+ if (TREE_CODE (string) == VIEW_CONVERT_EXPR)
+ string = TREE_OPERAND (string, 0);
+ cexpr_str cstr (string);
+ if (!cstr.type_check (tok->location))
+ return error_mark_node;
+ const char *msg;
+ int len;
+ if (!cstr.extract (tok->location, msg, len))
+ return error_mark_node;
+ parens.require_close (parser);
+ string = build_string (len, msg);
+ return string;
+ }
+ else if (!cp_parser_is_string_literal (tok))
+ {
+ error_at (tok->location,
+ "expected string-literal or constexpr in brackets");
+ return error_mark_node;
+ }
+ return cp_parser_string_literal (parser, false, false);
+}
+
/* Parse an asm-definition.
asm-qualifier:
asm-qualifier-list asm-qualifier
asm-definition:
- asm ( string-literal ) ;
+ asm ( constant-expr ) ;
GNU Extension:
asm-definition:
- asm asm-qualifier-list [opt] ( string-literal ) ;
- asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] ) ;
- asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( asm-string-expr ) ;
+ asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt]
: asm-operand-list [opt] ) ;
- asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt]
: asm-operand-list [opt]
: asm-clobber-list [opt] ) ;
- asm asm-qualifier-list [opt] ( string-literal : : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( asm-string-expr : : asm-operand-list [opt]
: asm-clobber-list [opt]
: asm-goto-list ) ;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return;
/* Look for the string. */
- tree string = cp_parser_string_literal (parser, /*translate=*/false,
- /*wide_ok=*/false);
+ tree string = cp_parser_asm_string_expression (parser);
if (string == error_mark_node)
{
cp_parser_skip_to_closing_parenthesis (parser, true, false,
/* Parse an (optional) asm-specification.
asm-specification:
- asm ( string-literal )
+ asm ( asm-string-expr )
If the asm-specification is present, returns a STRING_CST
corresponding to the string-literal. Otherwise, returns
parens.require_open (parser);
/* Look for the string-literal. */
- tree asm_specification = cp_parser_string_literal (parser,
- /*translate=*/false,
- /*wide_ok=*/false);
+ tree asm_specification = cp_parser_asm_string_expression (parser);
/* Look for the `)'. */
parens.require_close (parser);
asm-operand-list , asm-operand
asm-operand:
- string-literal ( expression )
- [ string-literal ] string-literal ( expression )
+ asm-string-expr ( expression )
+ [ asm-string-expr ] asm-string-expr ( expression )
Returns a TREE_LIST representing the operands. The TREE_VALUE of
each node is the expression. The TREE_PURPOSE is itself a
}
else
name = NULL_TREE;
- /* Look for the string-literal. */
- tree string_literal = cp_parser_string_literal (parser,
- /*translate=*/false,
- /*wide_ok=*/false);
+ /* Look for the string. */
+ tree string_literal = cp_parser_asm_string_expression (parser);
/* Look for the `('. */
matching_parens parens;
/* Parse an asm-clobber-list.
asm-clobber-list:
- string-literal
- asm-clobber-list , string-literal
+ const-expression
+ asm-clobber-list , const-expression
Returns a TREE_LIST, indicating the clobbers in the order that they
appeared. The TREE_VALUE of each node is a STRING_CST. */
while (true)
{
/* Look for the string literal. */
- tree string_literal = cp_parser_string_literal (parser,
- /*translate=*/false,
- /*wide_ok=*/false);
+ tree string_literal = cp_parser_asm_string_expression (parser);
/* Add it to the list. */
clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
/* If the next token is not a `,', then the list is
GCC does not parse the assembler instructions themselves and
does not know what they mean or even whether they are valid assembler input.
-You may place multiple assembler instructions together in a single @code{asm}
-string, separated by the characters normally used in assembly code for the
-system. A combination that works in most places is a newline to break the
+You may place multiple assembler instructions together in a single @code{asm}
+string, separated by the characters normally used in assembly code for the
+system. A combination that works in most places is a newline to break the
line, plus a tab character (written as @samp{\n\t}).
-Some assemblers allow semicolons as a line separator. However,
-note that some assembler dialects use semicolons to start a comment.
+Some assemblers allow semicolons as a line separator. However,
+note that some assembler dialects use semicolons to start a comment.
@end table
+@node asm constexprs
+With gnu++11 or later the string can also be a compile time constant expression
+inside parens. The constant expression can return a string or a container
+with data and size members, following similar rules as C++26 @code{static_assert}
+message. Any string is converted to the character set of the source code.
+When this feature is available the @code{__GXX_CONSTEXPR_ASM__} cpp symbol is defined.
+
+@example
+constexpr const char *genfoo() @{ return "foo"; @}
+
+void function()
+@{
+ asm((genfoo()));
+@}
+@end example
+
@subsubheading Remarks
Using extended @code{asm} (@pxref{Extended Asm}) typically produces
smaller, safer, and more efficient code, and in most cases it is a
@item AssemblerTemplate
This is a literal string that is the template for the assembler code. It is a
combination of fixed text and tokens that refer to the input, output,
-and goto parameters. @xref{AssemblerTemplate}.
+and goto parameters. @xref{AssemblerTemplate}. With gnu++11 or later it can
+also be a constant expression inside parens (see @ref{asm constexprs}).
@item OutputOperands
A comma-separated list of the C variables modified by the instructions in the
@var{AssemblerTemplate}. An empty list is permitted. @xref{OutputOperands}.
+With gnu++11 or later the strings can also be constant expressions inside parens
+(see @ref{asm constexprs})
@item InputOperands
A comma-separated list of C expressions read by the instructions in the
@var{AssemblerTemplate}. An empty list is permitted. @xref{InputOperands}.
+With gnu++11 or later the strings can also be constant expressions inside parens
+(see @ref{asm constexprs})
@item Clobbers
A comma-separated list of registers or other values changed by the
@var{AssemblerTemplate}, beyond those listed as outputs.
An empty list is permitted. @xref{Clobbers and Scratch Registers}.
+With gnu++11 or later the strings can also be constant expressions inside parens
+(see @ref{asm constexprs})
@item GotoLabels
When you are using the @code{goto} form of @code{asm}, this section contains
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-std=gnu++11" } */
+
+constexpr const char *genfoo ()
+{
+ return "foo %1,%0";
+}
+
+constexpr const char *genoutput ()
+{
+ return "=r";
+}
+
+constexpr const char *geninput ()
+{
+ return "r";
+}
+
+constexpr const char *genclobber ()
+{
+ return "memory";
+}
+
+void f()
+{
+ int a;
+ asm((genfoo ()) : (genoutput ()) (a) : (geninput ()) (1) : (genclobber ()));
+}
+
+/* { dg-final { scan-assembler "foo" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-std=gnu++11" } */
+
+using size_t = typeof(sizeof(0));
+template <typename T, size_t N>
+struct array {
+ constexpr size_t size () const { return N; }
+ constexpr const T *data () const { return a; }
+ const T a[N];
+};
+
+void f()
+{
+ int a;
+ asm((array<char, 3> {'f','o','o'}) :
+ (array<char, 2>{'=','r'}) (a) :
+ (array<char, 1>{'r'}) (1) :
+ (array<char, 6>{'m','e','m','o','r','y'}));
+}
+
+/* { dg-final { scan-assembler "foo" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-std=gnu++11" } */
+
+constexpr const char *genfoo ()
+{
+ return "foo %1,%0";
+}
+
+constexpr const char *genoutput ()
+{
+ return "=r";
+}
+
+constexpr const char *geninput ()
+{
+ return "r";
+}
+
+constexpr const char *genclobber ()
+{
+ return "memory";
+}
+
+void f()
+{
+ int a;
+ asm(genfoo () : /* { dg-error "expected string-literal or constexpr in brackets" } */
+ genoutput() (a) :
+ geninput() (1) :
+ genclobber());
+}
foo ()
{
int i;
- asm (); // { dg-error "expected string-literal before" }
- asm (1); // { dg-error "expected string-literal before" }
- asm (int); // { dg-error "expected string-literal before" }
- asm (: "=r" (i)); // { dg-error "expected string-literal before" }
- asm (1 : "=r" (i)); // { dg-error "expected string-literal before" }
- asm (int : "=r" (i)); // { dg-error "expected string-literal before" }
- asm (: : "r" (i)); // { dg-error "expected string-literal before" }
- asm (1 : : "r" (i)); // { dg-error "expected string-literal before" }
- asm (int : : "r" (i)); // { dg-error "expected string-literal before" }
- asm (: : : "memory"); // { dg-error "expected string-literal before" }
- asm (1 : : : "memory"); // { dg-error "expected string-literal before" }
+ asm (); // { dg-error "expected string-literal" }
+ asm (1); // { dg-error "expected string-literal" }
+ asm (int); // { dg-error "expected string-literal" }
+ asm (: "=r" (i)); // { dg-error "expected string-literal" }
+ asm (1 : "=r" (i)); // { dg-error "expected string-literal" }
+ asm (int : "=r" (i)); // { dg-error "expected string-literal" }
+ asm (: : "r" (i)); // { dg-error "expected string-literal" }
+ asm (1 : : "r" (i)); // { dg-error "expected string-literal" }
+ asm (int : : "r" (i)); // { dg-error "expected string-literal" }
+ asm (: : : "memory"); // { dg-error "expected string-literal" }
+ asm (1 : : : "memory"); // { dg-error "expected string-literal" }
}
void foo()
{
- asm("" ::: X); // { dg-error "before" }
+ asm("" ::: X); // { dg-error "string-literal" }
+ // { dg-error "before" "" { target *-*-* } .-1 }
}
void foo()
{
asm("" : 0); // { dg-error "numeric constant|token" }
+ // { dg-error "string-literal" "" { target *-*-* } .-1 }
}
void foo()
{
asm("" :: 0); // { dg-error "numeric constant|token" }
+ // { dg-error "string-literal" "" { target *-*-* } .-1 }
}
void foo()
{
asm ("%[x]" : [0](x)); // { dg-error "numeric constant|token" }
+ // { dg-error "string-literal" "" { target *-*-* } .-1 }
}