diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index bca0d8f..bbb12bb 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -518,11 +518,12 @@ referred to more than once in a single template that generates multiple assembler instructions. @samp{%} followed by a punctuation character specifies a substitution that -does not use an operand. Only one case is standard: @samp{%%} outputs a -@samp{%} into the assembler code. Other nonstandard cases can be -defined in the @code{PRINT_OPERAND} macro. You must also define -which punctuation characters are valid with the -@code{PRINT_OPERAND_PUNCT_VALID_P} macro. +does not use an operand. There are four standard cases: @samp{%%}, +@samp{%@{}, @samp{%@}} and @samp{%|} output @samp{%}, @samp{@{}, @samp{@}} +and @samp{|} respectively into the assembler code. Other nonstandard cases +can be defined in the @code{PRINT_OPERAND} macro. You must also define which +punctuation characters are valid with the @code{PRINT_OPERAND_PUNCT_VALID_P} +macro. @cindex \ @cindex backslash diff --git a/gcc/final.c b/gcc/final.c index ceb688e..833b1c3 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -3381,6 +3381,7 @@ output_asm_operand_names (rtx *operands, int *oporder, int nops) static const char * do_assembler_dialects (const char *p, int *dialect) { + int pcts = 0; char c = *(p - 1); switch (c) @@ -3398,8 +3399,14 @@ do_assembler_dialects (const char *p, int *dialect) DIALECT_NUMBER of strings ending with '|'. */ for (i = 0; i < dialect_number; i++) { - while (*p && *p != '}' && *p++ != '|') - ; + /* For a close brace to be the end of dialect alternatives it + must not be escaped by '%', i.e. '}' must follow an even number + of '%'s since %% stands for the percent sign in assembler code. */ + while (*p && !(*p == '}' && !(pcts % 2)) && *p++ != '|') + pcts = (*(p - 1) == '%') ? pcts + 1 : 0; + + pcts = 0; + if (*p == '}') break; } @@ -3420,8 +3427,13 @@ do_assembler_dialects (const char *p, int *dialect) output_operand_lossage ("unterminated assembly dialect alternative"); break; } + + pcts = (*(p - 1) == '%') ? pcts + 1 : 0; } - while (*p++ != '}'); + /* Check the number of '%'s followed by '{' as in previous case. */ + while (!(*p++ == '}' && !(pcts % 2))); + + pcts = 0; *dialect = 0; } else @@ -3515,10 +3527,10 @@ output_asm_insn (const char *templ, rtx *operands) case '%': /* %% outputs a single %. */ - if (*p == '%') + if (*p == '%' || *p == '{' || *p == '}' || *p == '|') { + putc (*p, asm_out_file); p++; - putc (c, asm_out_file); } /* %= outputs a number which is unique to each insn in the entire compilation. This is useful for making local labels that are diff --git a/gcc/testsuite/gcc.target/i386/asm-dialect-2.c b/gcc/testsuite/gcc.target/i386/asm-dialect-2.c new file mode 100644 index 0000000..942f505 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/asm-dialect-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-masm=att" } */ + +void f() +{ + /* Check for escaped curly braces support. */ + asm volatile ("{%%%{a%}%||%%%}b}" : :); +} + +/* { dg-final { scan-assembler "%{a}|\[^b\]" } } */