* [PATCH 1/2] asm qualifiers (PR55681)
2018-12-02 16:38 [PATCH v2 0/2] asm qualifiers (PR55681) and asm inline Segher Boessenkool
@ 2018-12-02 16:39 ` Segher Boessenkool
2018-12-03 22:20 ` Joseph Myers
2018-12-05 21:47 ` Jason Merrill
2018-12-02 16:40 ` [PATCH 2/2] asm inline Segher Boessenkool
2018-12-06 18:11 ` [PATCH v2 0/2] asm qualifiers (PR55681) and " Segher Boessenkool
2 siblings, 2 replies; 15+ messages in thread
From: Segher Boessenkool @ 2018-12-02 16:39 UTC (permalink / raw)
To: gcc-patches
Cc: jakub, Joseph Myers, jason, nathan, polacek, Segher Boessenkool
PR55681 observes that currently only one qualifier is allowed for
inline asm, so that e.g. "volatile asm" is allowed, "const asm" is also
okay (with a warning), but "const volatile asm" gives an error. Also
"goto" has to be last.
This patch changes things so that only "asm-qualifiers" are allowed,
that is "volatile" and "goto", in any combination, in any order, but
without repetitions.
2018-12-02 Segher Boessenkool <segher@kernel.crashing.org>
PR inline-asm/55681
* doc/extend.texi (Basic Asm): Update grammar.
(Extended Asm): Update grammar.
gcc/c/
PR inline-asm/55681
* c-parser.c (c_parser_for_statement): Update grammar. Allow any
combination of volatile and goto, in any order, without repetitions.
gcc/cp/
PR inline-asm/55681
* parser.c (cp_parser_using_directive): Update grammar. Allow any
combination of volatile and goto, in any order, without repetitions.
gcc/testsuite/
PR inline-asm/55681
* gcc.dg/asm-qual-1.c: Test that "const" and "restrict" are refused.
* gcc.dg/asm-qual-2.c: New test, test that asm-qualifiers are allowed
in any order, but that duplicates are not allowed.
---
gcc/c/c-parser.c | 74 +++++++++++++++++++++----------------
gcc/cp/parser.c | 77 ++++++++++++++++++++++++++-------------
gcc/doc/extend.texi | 8 ++--
gcc/testsuite/gcc.dg/asm-qual-1.c | 10 +++--
gcc/testsuite/gcc.dg/asm-qual-2.c | 21 +++++++++++
5 files changed, 127 insertions(+), 63 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/asm-qual-2.c
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index afc4071..e516f9a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -6329,60 +6329,72 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
}
/* Parse an asm statement, a GNU extension. This is a full-blown asm
- statement with inputs, outputs, clobbers, and volatile tag
+ statement with inputs, outputs, clobbers, and volatile and goto tag
allowed.
+ asm-qualifier:
+ volatile
+ goto
+
+ asm-qualifier-list:
+ asm-qualifier-list asm-qualifier
+ asm-qualifier
+
asm-statement:
- asm type-qualifier[opt] ( asm-argument ) ;
- asm type-qualifier[opt] goto ( asm-goto-argument ) ;
+ asm asm-qualifier-list[opt] ( asm-argument ) ;
asm-argument:
asm-string-literal
asm-string-literal : asm-operands[opt]
asm-string-literal : asm-operands[opt] : asm-operands[opt]
- asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers[opt]
-
- asm-goto-argument:
+ asm-string-literal : asm-operands[opt] : asm-operands[opt] \
+ : asm-clobbers[opt]
asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \
: asm-goto-operands
- Qualifiers other than volatile are accepted in the syntax but
- warned for. */
+ The form with asm-goto-operands is valid if and only if the
+ asm-qualifier-list contains goto, and is the only allowed form in that case.
+ Duplicate asm-qualifiers are not allowed. */
static tree
c_parser_asm_statement (c_parser *parser)
{
tree quals, str, outputs, inputs, clobbers, labels, ret;
- bool simple, is_goto;
+ bool simple, is_volatile, is_goto;
location_t asm_loc = c_parser_peek_token (parser)->location;
int section, nsections;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
c_parser_consume_token (parser);
- if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
- {
- quals = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
- }
- else if (c_parser_next_token_is_keyword (parser, RID_CONST)
- || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
- {
- warning_at (c_parser_peek_token (parser)->location,
- 0,
- "%E qualifier ignored on asm",
- c_parser_peek_token (parser)->value);
- quals = NULL_TREE;
- c_parser_consume_token (parser);
- }
- else
- quals = NULL_TREE;
+ quals = NULL_TREE;
+ is_volatile = false;
is_goto = false;
- if (c_parser_next_token_is_keyword (parser, RID_GOTO))
- {
- c_parser_consume_token (parser);
- is_goto = true;
- }
+ for (bool done = false; !done; )
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_VOLATILE:
+ if (!is_volatile)
+ {
+ is_volatile = true;
+ quals = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ done = true;
+ break;
+ case RID_GOTO:
+ if (!is_goto)
+ {
+ is_goto = true;
+ c_parser_consume_token (parser);
+ }
+ else
+ done = true;
+ break;
+ default:
+ done = true;
+ }
/* ??? Follow the C++ parser rather than using the
lex_untranslated_string kludge. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 3a98ed9..9c43683 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19537,22 +19537,34 @@ cp_parser_using_directive (cp_parser* parser)
/* Parse an asm-definition.
+ asm-qualifier:
+ volatile
+ goto
+
+ asm-qualifier-list:
+ asm-qualifier
+ asm-qualifier-list asm-qualifier
+
asm-definition:
asm ( string-literal ) ;
GNU Extension:
asm-definition:
- asm volatile [opt] ( string-literal ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt]
+ 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-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ : asm-operand-list [opt]
: asm-clobber-list [opt] ) ;
- asm volatile [opt] goto ( string-literal : : asm-operand-list [opt]
- : asm-clobber-list [opt]
- : asm-goto-list ) ; */
+ asm asm-qualifier-list [opt] ( string-literal : : asm-operand-list [opt]
+ : asm-clobber-list [opt]
+ : asm-goto-list ) ;
+
+ The form with asm-goto-list is valid if and only if the asm-qualifier-list
+ contains goto, and is the only allowed form in that case. No duplicates are
+ allowed in an asm-qualifier-list. */
static void
cp_parser_asm_definition (cp_parser* parser)
@@ -19581,23 +19593,36 @@ cp_parser_asm_definition (cp_parser* parser)
}
/* See if the next token is `volatile'. */
- if (cp_parser_allow_gnu_extensions_p (parser)
- && cp_lexer_next_token_is_keyword (parser->lexer, RID_VOLATILE))
- {
- /* Remember that we saw the `volatile' keyword. */
- volatile_p = true;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- }
- if (cp_parser_allow_gnu_extensions_p (parser)
- && parser->in_function_body
- && cp_lexer_next_token_is_keyword (parser->lexer, RID_GOTO))
- {
- /* Remember that we saw the `goto' keyword. */
- goto_p = true;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- }
+ if (cp_parser_allow_gnu_extensions_p (parser))
+ for (bool done = false; !done ; )
+ switch (cp_lexer_peek_token (parser->lexer)->keyword)
+ {
+ case RID_VOLATILE:
+ if (!volatile_p)
+ {
+ /* Remember that we saw the `volatile' keyword. */
+ volatile_p = true;
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ done = true;
+ break;
+ case RID_GOTO:
+ if (!goto_p && parser->in_function_body)
+ {
+ /* Remember that we saw the `goto' keyword. */
+ goto_p = true;
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ done = true;
+ break;
+ default:
+ done = true;
+ }
+
/* Look for the opening `('. */
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 4e8be5b..2791f25 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -8369,7 +8369,7 @@ for a C symbol, or to place a C variable in a specific register.
A basic @code{asm} statement has the following syntax:
@example
-asm @r{[} volatile @r{]} ( @var{AssemblerInstructions} )
+asm @var{asm-qualifiers} ( @var{AssemblerInstructions} )
@end example
The @code{asm} keyword is a GNU extension.
@@ -8497,17 +8497,19 @@ Extended @code{asm} syntax uses colons (@samp{:}) to delimit
the operand parameters after the assembler template:
@example
-asm @r{[}volatile@r{]} ( @var{AssemblerTemplate}
+asm @var{asm-qualifiers} ( @var{AssemblerTemplate}
: @var{OutputOperands}
@r{[} : @var{InputOperands}
@r{[} : @var{Clobbers} @r{]} @r{]})
-asm @r{[}volatile@r{]} goto ( @var{AssemblerTemplate}
+asm @var{asm-qualifiers} ( @var{AssemblerTemplate}
:
: @var{InputOperands}
: @var{Clobbers}
: @var{GotoLabels})
@end example
+where in the last form, @var{asm-qualifiers} contains @code{goto} (and in the
+first form, not).
The @code{asm} keyword is a GNU extension.
When writing code that can be compiled with @option{-ansi} and the
diff --git a/gcc/testsuite/gcc.dg/asm-qual-1.c b/gcc/testsuite/gcc.dg/asm-qual-1.c
index 5ec9a29..cb37283 100644
--- a/gcc/testsuite/gcc.dg/asm-qual-1.c
+++ b/gcc/testsuite/gcc.dg/asm-qual-1.c
@@ -1,4 +1,4 @@
-/* Test that qualifiers other than volatile are ignored on asm. */
+/* Test that qualifiers other than volatile are disallowed on asm. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99" } */
@@ -7,6 +7,10 @@ void
f (void)
{
asm volatile ("");
- asm const (""); /* { dg-warning "const qualifier ignored on asm" } */
- asm restrict (""); /* { dg-warning "restrict qualifier ignored on asm" } */
+
+ asm const (""); /* { dg-error {expected '\(' before 'const'} } */
+ /* { dg-error {expected identifier} {} {target *-*-*} .-1 } */
+
+ asm restrict (""); /* { dg-error {expected '\(' before 'restrict'} } */
+ /* { dg-error {expected identifier} {} {target *-*-*} .-1 } */
}
diff --git a/gcc/testsuite/gcc.dg/asm-qual-2.c b/gcc/testsuite/gcc.dg/asm-qual-2.c
new file mode 100644
index 0000000..37df2ad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-qual-2.c
@@ -0,0 +1,21 @@
+/* Test that qualifiers on asm are allowed in any order. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+void
+f (void)
+{
+ asm volatile goto ("" :::: lab);
+ asm goto volatile ("" :::: lab);
+
+ /* Duplicates are not allowed. */
+ asm goto volatile volatile ("" :::: lab); /* { dg-error "" } */
+ asm volatile goto volatile ("" :::: lab); /* { dg-error "" } */
+ asm volatile volatile goto ("" :::: lab); /* { dg-error "" } */
+ asm goto goto volatile ("" :::: lab); /* { dg-error "" } */
+ asm goto volatile goto ("" :::: lab); /* { dg-error "" } */
+ asm volatile goto goto ("" :::: lab); /* { dg-error "" } */
+
+lab:
+ ;
+}
--
1.8.3.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/2] asm inline
2018-12-02 16:38 [PATCH v2 0/2] asm qualifiers (PR55681) and asm inline Segher Boessenkool
2018-12-02 16:39 ` [PATCH 1/2] asm qualifiers (PR55681) Segher Boessenkool
@ 2018-12-02 16:40 ` Segher Boessenkool
2018-12-02 17:23 ` Marc Glisse
2018-12-04 15:31 ` Richard Sandiford
2018-12-06 18:11 ` [PATCH v2 0/2] asm qualifiers (PR55681) and " Segher Boessenkool
2 siblings, 2 replies; 15+ messages in thread
From: Segher Boessenkool @ 2018-12-02 16:40 UTC (permalink / raw)
To: gcc-patches
Cc: jakub, Joseph Myers, jason, nathan, polacek, Segher Boessenkool
The Linux kernel people want a feature that makes GCC pretend some
inline assembler code is tiny (while it would think it is huge), so
that such code will be inlined essentially always instead of
essentially never.
This patch lets you say "asm inline" instead of just "asm", with the
result that that inline assembler is always counted as minimum cost
for inlining. It implements this for C and C++, making "inline"
another asm-qualifier (supplementing "volatile" and "goto").
2018-12-02 Segher Boessenkool <segher@kernel.crashing.org>
* doc/extend.texi (Using Assembly Language with C): Document asm inline.
(Size of an asm): Fix typo. Document asm inline.
* gimple-pretty-print.c (dump_gimple_asm): Handle asm inline.
* gimple.h (enum gf_mask): Add GF_ASM_INLINE.
(gimple_asm_set_volatile): Fix typo.
(gimple_asm_inline_p): New.
(gimple_asm_set_inline): New.
* gimplify.c (gimplify_asm_expr): Propagate the asm inline flag from
tree to gimple.
* ipa-icf-gimple.c (func_checker::compare_gimple_asm): Compare the
gimple_asm_inline_p flag, too.
* tree-core.h (tree_base): Document that protected_flag is ASM_INLINE_P
in an ASM_EXPR.
* tree-inline.c (estimate_num_insns): If gimple_asm_inline_p return
a minimum size for an asm.
* tree.h (ASM_INLINE_P): New.
gcc/c/
* c-parser.c (c_parser_asm_statement): Detect the inline keyword
after asm. Pass a flag for it to build_asm_expr.
* c-tree.h (build_asm_expr): Update declaration.
* c-typeck.c (build_asm_stmt): Add is_inline parameter. Use it to
set ASM_INLINE_P.
gcc/cp/
* cp-tree.h (finish_asm_stmt): Update declaration.
* parser.c (cp_parser_asm_definition): Detect the inline keyword
after asm. Pass a flag for it to finish_asm_stmt.
* pt.c (tsubst_expr): Pass the ASM_INLINE_P flag to finish_asm_stmt.
* semantics.c (finish_asm_stmt): Add inline_p parameter. Use it to
set ASM_INLINE_P.
gcc/testsuite/
* c-c++-common/torture/asm-inline.c: New testcase.
* gcc.dg/asm-qual-2.c: Test asm inline, too.
---
gcc/c/c-parser.c | 21 ++++++++--
gcc/c/c-tree.h | 3 +-
gcc/c/c-typeck.c | 3 +-
gcc/cp/cp-tree.h | 2 +-
gcc/cp/parser.c | 15 ++++++-
gcc/cp/pt.c | 2 +-
gcc/cp/semantics.c | 3 +-
gcc/doc/extend.texi | 15 ++++++-
gcc/gimple-pretty-print.c | 2 +
gcc/gimple.h | 24 ++++++++++-
gcc/gimplify.c | 1 +
gcc/ipa-icf-gimple.c | 3 ++
gcc/testsuite/c-c++-common/torture/asm-inline.c | 53 +++++++++++++++++++++++++
gcc/testsuite/gcc.dg/asm-qual-2.c | 25 ++++++++++++
gcc/tree-core.h | 3 ++
gcc/tree-inline.c | 3 ++
gcc/tree.h | 3 ++
17 files changed, 169 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/torture/asm-inline.c
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index e516f9a..921363d 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -6329,11 +6329,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
}
/* Parse an asm statement, a GNU extension. This is a full-blown asm
- statement with inputs, outputs, clobbers, and volatile and goto tag
- allowed.
+ statement with inputs, outputs, clobbers, and volatile, inline, and goto
+ tags allowed.
asm-qualifier:
volatile
+ inline
goto
asm-qualifier-list:
@@ -6360,7 +6361,7 @@ static tree
c_parser_asm_statement (c_parser *parser)
{
tree quals, str, outputs, inputs, clobbers, labels, ret;
- bool simple, is_volatile, is_goto;
+ bool simple, is_volatile, is_inline, is_goto;
location_t asm_loc = c_parser_peek_token (parser)->location;
int section, nsections;
@@ -6369,6 +6370,7 @@ c_parser_asm_statement (c_parser *parser)
quals = NULL_TREE;
is_volatile = false;
+ is_inline = false;
is_goto = false;
for (bool done = false; !done; )
switch (c_parser_peek_token (parser)->keyword)
@@ -6383,6 +6385,16 @@ c_parser_asm_statement (c_parser *parser)
else
done = true;
break;
+ case RID_INLINE:
+ if (!is_inline)
+ {
+ is_inline = true;
+ quals = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ done = true;
+ break;
case RID_GOTO:
if (!is_goto)
{
@@ -6471,7 +6483,8 @@ c_parser_asm_statement (c_parser *parser)
c_parser_skip_to_end_of_block_or_statement (parser);
ret = build_asm_stmt (quals, build_asm_expr (asm_loc, str, outputs, inputs,
- clobbers, labels, simple));
+ clobbers, labels, simple,
+ is_inline));
error:
parser->lex_untranslated_string = false;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 5ed2f48..f08a8fc 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -677,7 +677,8 @@ extern tree build_compound_literal (location_t, tree, tree, bool,
extern void check_compound_literal_type (location_t, struct c_type_name *);
extern tree c_start_case (location_t, location_t, tree, bool);
extern void c_finish_case (tree, tree);
-extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool);
+extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool,
+ bool);
extern tree build_asm_stmt (tree, tree);
extern int c_types_compatible_p (tree, tree);
extern tree c_begin_compound_stmt (bool);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 81c520a..9b572d7 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10315,7 +10315,7 @@ build_asm_stmt (tree cv_qualifier, tree args)
are subtly different. We use a ASM_EXPR node to represent this. */
tree
build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
- tree clobbers, tree labels, bool simple)
+ tree clobbers, tree labels, bool simple, bool is_inline)
{
tree tail;
tree args;
@@ -10433,6 +10433,7 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
as volatile. */
ASM_INPUT_P (args) = simple;
ASM_VOLATILE_P (args) = (noutputs == 0);
+ ASM_INLINE_P (args) = is_inline;
return args;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 111a123..26acf31 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6996,7 +6996,7 @@ extern tree begin_compound_stmt (unsigned int);
extern void finish_compound_stmt (tree);
extern tree finish_asm_stmt (int, tree, tree, tree, tree,
- tree);
+ tree, bool);
extern tree finish_label_stmt (tree);
extern void finish_label_decl (tree);
extern cp_expr finish_parenthesized_expr (cp_expr);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 9c43683..64d073e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19539,6 +19539,7 @@ cp_parser_using_directive (cp_parser* parser)
asm-qualifier:
volatile
+ inline
goto
asm-qualifier-list:
@@ -19579,6 +19580,7 @@ cp_parser_asm_definition (cp_parser* parser)
bool extended_p = false;
bool invalid_inputs_p = false;
bool invalid_outputs_p = false;
+ bool inline_p = false;
bool goto_p = false;
required_token missing = RT_NONE;
@@ -19608,6 +19610,17 @@ cp_parser_asm_definition (cp_parser* parser)
else
done = true;
break;
+ case RID_INLINE:
+ if (!inline_p && parser->in_function_body)
+ {
+ /* Remember that we saw the `inline' keyword. */
+ inline_p = true;
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ done = true;
+ break;
case RID_GOTO:
if (!goto_p && parser->in_function_body)
{
@@ -19749,7 +19762,7 @@ cp_parser_asm_definition (cp_parser* parser)
if (parser->in_function_body)
{
asm_stmt = finish_asm_stmt (volatile_p, string, outputs,
- inputs, clobbers, labels);
+ inputs, clobbers, labels, inline_p);
/* If the extended syntax was not used, mark the ASM_EXPR. */
if (!extended_p)
{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a0d899f..7d846a0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17226,7 +17226,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
tree labels = tsubst_copy_asm_operands (ASM_LABELS (t), args,
complain, in_decl);
tmp = finish_asm_stmt (ASM_VOLATILE_P (t), string, outputs, inputs,
- clobbers, labels);
+ clobbers, labels, ASM_INLINE_P (t));
tree asm_expr = tmp;
if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR)
asm_expr = TREE_OPERAND (asm_expr, 0);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 733c42f..87d54b1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1486,7 +1486,7 @@ finish_compound_stmt (tree stmt)
tree
finish_asm_stmt (int volatile_p, tree string, tree output_operands,
- tree input_operands, tree clobbers, tree labels)
+ tree input_operands, tree clobbers, tree labels, bool inline_p)
{
tree r;
tree t;
@@ -1640,6 +1640,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands,
output_operands, input_operands,
clobbers, labels);
ASM_VOLATILE_P (r) = volatile_p || noutputs == 0;
+ ASM_INLINE_P (r) = inline_p;
r = maybe_cleanup_point_expr_void (r);
return add_stmt (r);
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 2791f25..cebbfc7 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -8382,6 +8382,10 @@ various @option{-std} options, use @code{__asm__} instead of
@item volatile
The optional @code{volatile} qualifier has no effect.
All basic @code{asm} blocks are implicitly volatile.
+
+@item inline
+If you use the @code{inline} qualifier, then for inlining purposes the size
+of the asm is taken as the smallest size possible (@pxref{Size of an asm}).
@end table
@subsubheading Parameters
@@ -8525,6 +8529,10 @@ values to produce output values. However, your @code{asm} statements may
also produce side effects. If so, you may need to use the @code{volatile}
qualifier to disable certain optimizations. @xref{Volatile}.
+@item inline
+If you use the @code{inline} qualifier, then for inlining purposes the size
+of the asm is taken as the smallest size possible (@pxref{Size of an asm}).
+
@item goto
This qualifier informs the compiler that the @code{asm} statement may
perform a jump to one of the labels listed in the @var{GotoLabels}.
@@ -9983,7 +9991,7 @@ does this by counting the number of instructions in the pattern of the
@code{asm} and multiplying that by the length of the longest
instruction supported by that processor. (When working out the number
of instructions, it assumes that any occurrence of a newline or of
-whatever statement separator character is supported by the assembler --
+whatever statement separator character is supported by the assembler ---
typically @samp{;} --- indicates the end of an instruction.)
Normally, GCC's estimate is adequate to ensure that correct
@@ -9994,6 +10002,11 @@ space in the object file than is needed for a single instruction.
If this happens then the assembler may produce a diagnostic saying that
a label is unreachable.
+@cindex @code{asm inline}
+This size is also used for inlining decisions. If you use @code{asm inline}
+instead of just @code{asm}, then for inlining purposes the size of the asm
+is taken as the minimum size, ignoring how many instructions GCC thinks it is.
+
@node Alternate Keywords
@section Alternate Keywords
@cindex alternate keywords
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 276e579..51c0fb3 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -2048,6 +2048,8 @@ dump_gimple_asm (pretty_printer *buffer, gasm *gs, int spc, dump_flags_t flags)
pp_string (buffer, "__asm__");
if (gimple_asm_volatile_p (gs))
pp_string (buffer, " __volatile__");
+ if (gimple_asm_inline_p (gs))
+ pp_string (buffer, " __inline__");
if (gimple_asm_nlabels (gs))
pp_string (buffer, " goto");
pp_string (buffer, "(\"");
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 9853521..0d0ee16 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -137,6 +137,7 @@ enum gimple_rhs_class
enum gf_mask {
GF_ASM_INPUT = 1 << 0,
GF_ASM_VOLATILE = 1 << 1,
+ GF_ASM_INLINE = 1 << 2,
GF_CALL_FROM_THUNK = 1 << 0,
GF_CALL_RETURN_SLOT_OPT = 1 << 1,
GF_CALL_TAILCALL = 1 << 2,
@@ -3920,7 +3921,7 @@ gimple_asm_volatile_p (const gasm *asm_stmt)
}
-/* If VOLATLE_P is true, mark asm statement ASM_STMT as volatile. */
+/* If VOLATILE_P is true, mark asm statement ASM_STMT as volatile. */
static inline void
gimple_asm_set_volatile (gasm *asm_stmt, bool volatile_p)
@@ -3932,6 +3933,27 @@ gimple_asm_set_volatile (gasm *asm_stmt, bool volatile_p)
}
+/* Return true ASM_STMT ASM_STMT is an asm statement marked inline. */
+
+static inline bool
+gimple_asm_inline_p (const gasm *asm_stmt)
+{
+ return (asm_stmt->subcode & GF_ASM_INLINE) != 0;
+}
+
+
+/* If INLINE_P is true, mark asm statement ASM_STMT as inline. */
+
+static inline void
+gimple_asm_set_inline (gasm *asm_stmt, bool inline_p)
+{
+ if (inline_p)
+ asm_stmt->subcode |= GF_ASM_INLINE;
+ else
+ asm_stmt->subcode &= ~GF_ASM_INLINE;
+}
+
+
/* If INPUT_P is true, mark asm ASM_STMT as an ASM_INPUT. */
static inline void
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 40fbaa2..0e95ff2 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -6357,6 +6357,7 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
gimple_asm_set_volatile (stmt, ASM_VOLATILE_P (expr) || noutputs == 0);
gimple_asm_set_input (stmt, ASM_INPUT_P (expr));
+ gimple_asm_set_inline (stmt, ASM_INLINE_P (expr));
gimplify_seq_add_stmt (pre_p, stmt);
}
diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index ba39ea3..5361139 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -993,6 +993,9 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
if (gimple_asm_input_p (g1) != gimple_asm_input_p (g2))
return false;
+ if (gimple_asm_inline_p (g1) != gimple_asm_inline_p (g2))
+ return false;
+
if (gimple_asm_ninputs (g1) != gimple_asm_ninputs (g2))
return false;
diff --git a/gcc/testsuite/c-c++-common/torture/asm-inline.c b/gcc/testsuite/c-c++-common/torture/asm-inline.c
new file mode 100644
index 0000000..dea8965
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/asm-inline.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* -O0 does no inlining, and -O3 does it too aggressively for this test: */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O3" } { "" } }
+/* The normal asm is not inlined: */
+/* { dg-final { scan-assembler-times "w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w" 2 } } */
+/* But the asm inline is inlined: */
+/* { dg-final { scan-assembler-times "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x" 8 } } */
+
+static void f(void)
+{
+ asm ("w\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\n"
+ "w\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw");
+}
+
+int f0(void) { f(); return 0; }
+int f1(void) { f(); return 1; }
+int f2(void) { f(); return 2; }
+int f3(void) { f(); return 3; }
+
+static void fg(void)
+{
+ asm goto("w\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\n"
+ "w\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw\nw" :::: q);
+ q: ;
+}
+
+int fg0(void) { fg(); return 0; }
+int fg1(void) { fg(); return 1; }
+int fg2(void) { fg(); return 2; }
+int fg3(void) { fg(); return 3; }
+
+static void g(void)
+{
+ asm inline("x\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n"
+ "x\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx");
+}
+
+int g0(void) { g(); return 0; }
+int g1(void) { g(); return 1; }
+int g2(void) { g(); return 2; }
+int g3(void) { g(); return 3; }
+
+static void gg(void)
+{
+ asm inline goto("x\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n"
+ "x\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx" :::: q);
+ q: ;
+}
+
+int gg0(void) { gg(); return 0; }
+int gg1(void) { gg(); return 1; }
+int gg2(void) { gg(); return 2; }
+int gg3(void) { gg(); return 3; }
diff --git a/gcc/testsuite/gcc.dg/asm-qual-2.c b/gcc/testsuite/gcc.dg/asm-qual-2.c
index 37df2ad..79135c3 100644
--- a/gcc/testsuite/gcc.dg/asm-qual-2.c
+++ b/gcc/testsuite/gcc.dg/asm-qual-2.c
@@ -6,7 +6,18 @@ void
f (void)
{
asm volatile goto ("" :::: lab);
+ asm volatile inline ("" :::);
+ asm inline volatile ("" :::);
+ asm inline goto ("" :::: lab);
asm goto volatile ("" :::: lab);
+ asm goto inline ("" :::: lab);
+
+ asm volatile inline goto ("" :::: lab);
+ asm volatile goto inline ("" :::: lab);
+ asm inline volatile goto ("" :::: lab);
+ asm inline goto volatile ("" :::: lab);
+ asm goto volatile inline ("" :::: lab);
+ asm goto inline volatile ("" :::: lab);
/* Duplicates are not allowed. */
asm goto volatile volatile ("" :::: lab); /* { dg-error "" } */
@@ -16,6 +27,20 @@ f (void)
asm goto volatile goto ("" :::: lab); /* { dg-error "" } */
asm volatile goto goto ("" :::: lab); /* { dg-error "" } */
+ asm inline volatile volatile ("" :::); /* { dg-error "" } */
+ asm volatile inline volatile ("" :::); /* { dg-error "" } */
+ asm volatile volatile inline ("" :::); /* { dg-error "" } */
+ asm inline inline volatile ("" :::); /* { dg-error "" } */
+ asm inline volatile inline ("" :::); /* { dg-error "" } */
+ asm volatile inline inline ("" :::); /* { dg-error "" } */
+
+ asm goto inline inline ("" :::: lab); /* { dg-error "" } */
+ asm inline goto inline ("" :::: lab); /* { dg-error "" } */
+ asm inline inline goto ("" :::: lab); /* { dg-error "" } */
+ asm goto goto inline ("" :::: lab); /* { dg-error "" } */
+ asm goto inline goto ("" :::: lab); /* { dg-error "" } */
+ asm inline goto goto ("" :::: lab); /* { dg-error "" } */
+
lab:
;
}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index cec95e7..e7646af 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1193,6 +1193,9 @@ struct GTY(()) tree_base {
OMP_CLAUSE_LINEAR_VARIABLE_STRIDE in
OMP_CLAUSE_LINEAR
+ ASM_INLINE_P in
+ ASM_EXPR
+
side_effects_flag:
TREE_SIDE_EFFECTS in
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 5aa782b..7e9ed99 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4109,6 +4109,9 @@ estimate_num_insns (gimple *stmt, eni_weights *weights)
with very long asm statements. */
if (count > 1000)
count = 1000;
+ /* If this asm is asm inline, count anything as minimum size. */
+ if (gimple_asm_inline_p (as_a <gasm *> (stmt)))
+ count = !!count;
return MAX (1, count);
}
diff --git a/gcc/tree.h b/gcc/tree.h
index 0767ee8..76147f3 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1245,6 +1245,9 @@ extern tree maybe_wrap_with_location (tree, location_t);
ASM_OPERAND with no operands. */
#define ASM_INPUT_P(NODE) (ASM_EXPR_CHECK (NODE)->base.static_flag)
#define ASM_VOLATILE_P(NODE) (ASM_EXPR_CHECK (NODE)->base.public_flag)
+/* Nonzero if we want to consider this asm as minimum length and cost
+ for inlining decisions. */
+#define ASM_INLINE_P(NODE) (ASM_EXPR_CHECK (NODE)->base.protected_flag)
/* COND_EXPR accessors. */
#define COND_EXPR_COND(NODE) (TREE_OPERAND (COND_EXPR_CHECK (NODE), 0))
--
1.8.3.1
^ permalink raw reply [flat|nested] 15+ messages in thread