2013-05-06 Maxim Kuznetsov * final.c (do_assembler_dialects): Don't handle curly braces and vertical bar escaped by % as dialect delimiters. (output_asm_insn): Print curly braces and vertical bar if escaped by % and ASSEMBLER_DIALECT defined. * doc/tm.texi (ASSEMBLER_DIALECT): Document new standard escapes. * gcc.target/i386/asm-dialect-2.c: New testcase. 2012-07-25 Siddhesh Poyarekar * final.c [ASSEMBLER_DIALECT](do_assembler_dialects): New function to implement assembler dialects. (output_asm_insn): Use do_assembler_dialects. (asm_fprintf): Likewise. * gcc.target/i386/asm-dialect-1.c: New test case. --- gcc/final.c (revision 189853, 198640) +++ gcc/final.c (revision 189854, 198641) @@ -3134,6 +3134,96 @@ output_asm_operand_names (rtx *operands, } } +#ifdef ASSEMBLER_DIALECT +/* Helper function to parse assembler dialects in the asm string. + This is called from output_asm_insn and asm_fprintf. */ +static const char * +do_assembler_dialects (const char *p, int *dialect) +{ + char c = *(p - 1); + + switch (c) + { + case '{': + { + int i; + + if (*dialect) + output_operand_lossage ("nested assembly dialect alternatives"); + else + *dialect = 1; + + /* If we want the first dialect, do nothing. Otherwise, skip + DIALECT_NUMBER of strings ending with '|'. */ + for (i = 0; i < dialect_number; i++) + { + while (*p && *p != '}') + { + if (*p == '|') + { + p++; + break; + } + + /* Skip over any character after a percent sign. */ + if (*p == '%') + p++; + if (*p) + p++; + } + + if (*p == '}') + break; + } + + if (*p == '\0') + output_operand_lossage ("unterminated assembly dialect alternative"); + } + break; + + case '|': + if (*dialect) + { + /* Skip to close brace. */ + do + { + if (*p == '\0') + { + output_operand_lossage ("unterminated assembly dialect alternative"); + break; + } + + /* Skip over any character after a percent sign. */ + if (*p == '%' && p[1]) + { + p += 2; + continue; + } + + if (*p++ == '}') + break; + } + while (1); + + *dialect = 0; + } + else + putc (c, asm_out_file); + break; + + case '}': + if (! *dialect) + putc (c, asm_out_file); + *dialect = 0; + break; + default: + gcc_unreachable (); + } + + return p; +} +#endif + /* Output text from TEMPLATE to the assembler output file, obeying %-directions to substitute operands taken from the vector OPERANDS. @@ -3200,63 +3290,24 @@ output_asm_insn (const char *templ, rtx #ifdef ASSEMBLER_DIALECT case '{': - { - int i; - - if (dialect) - output_operand_lossage ("nested assembly dialect alternatives"); - else - dialect = 1; - - /* If we want the first dialect, do nothing. Otherwise, skip - DIALECT_NUMBER of strings ending with '|'. */ - for (i = 0; i < dialect_number; i++) - { - while (*p && *p != '}' && *p++ != '|') - ; - if (*p == '}') - break; - if (*p == '|') - p++; - } - - if (*p == '\0') - output_operand_lossage ("unterminated assembly dialect alternative"); - } - break; - - case '|': - if (dialect) - { - /* Skip to close brace. */ - do - { - if (*p == '\0') - { - output_operand_lossage ("unterminated assembly dialect alternative"); - break; - } - } - while (*p++ != '}'); - dialect = 0; - } - else - putc (c, asm_out_file); - break; - case '}': - if (! dialect) - putc (c, asm_out_file); - dialect = 0; + case '|': + p = do_assembler_dialects (p, &dialect); break; #endif case '%': - /* %% outputs a single %. */ - if (*p == '%') + /* %% outputs a single %. %{, %} and %| print {, } and | respectively + if ASSEMBLER_DIALECT defined and these characters have a special + meaning as dialect delimiters.*/ + if (*p == '%' +#ifdef ASSEMBLER_DIALECT + || *p == '{' || *p == '}' || *p == '|' +#endif + ) { + 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 @@ -3600,6 +3651,9 @@ asm_fprintf (FILE *file, const char *p, { char buf[10]; char *q, c; +#ifdef ASSEMBLER_DIALECT + int dialect = 0; +#endif va_list argptr; va_start (argptr, p); @@ -3611,29 +3665,9 @@ asm_fprintf (FILE *file, const char *p, { #ifdef ASSEMBLER_DIALECT case '{': - { - int i; - - /* If we want the first dialect, do nothing. Otherwise, skip - DIALECT_NUMBER of strings ending with '|'. */ - for (i = 0; i < dialect_number; i++) - { - while (*p && *p++ != '|') - ; - - if (*p == '|') - p++; - } - } - break; - - case '|': - /* Skip to close brace. */ - while (*p && *p++ != '}') - ; - break; - case '}': + case '|': + p = do_assembler_dialects (p, &dialect); break; #endif --- gcc/doc/tm.texi (revision 198640) +++ gcc/doc/tm.texi (revision 198641) @@ -8274,7 +8274,9 @@ first argument of @code{asm_fprintf}. T @code{ASSEMBLER_DIALECT} is zero, one, two, etc. Any special characters within these strings retain their usual meaning. If there are fewer alternatives within the braces than the value of -@code{ASSEMBLER_DIALECT}, the construct outputs nothing. +@code{ASSEMBLER_DIALECT}, the construct outputs nothing. If it's needed +to print curly braces or @samp{|} character in assembler output directly, +@samp{%@{}, @samp{%@}} and @samp{%|} can be used. If you do not define this macro, the characters @samp{@{}, @samp{|} and @samp{@}} do not have any special meaning when used in templates or --- gcc/testsuite/gcc.target/i386/asm-dialect-1.c (revision 0) +++ gcc/testsuite/gcc.target/i386/asm-dialect-1.c (revision 189854) @@ -0,0 +1,15 @@ +/* { dg-options "-masm=intel" } */ + +extern void abort (void); + +int +main (void) +{ + int f = 0; + asm ("{movl $42, %%eax | mov eax, 42}" : :); + asm ("{movl $41, %0||mov %0, 43}" : "=r"(f)); + if (f != 42) + abort (); + + return 0; +} --- gcc/testsuite/gcc.target/i386/asm-dialect-2.c (revision 0) +++ gcc/testsuite/gcc.target/i386/asm-dialect-2.c (revision 198641) @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-masm=att" } */ +/* { dg-final { scan-assembler "%{a}|" } } */ + +int a, b; + +void f() +{ + /* Check for escaped curly braces support. */ + asm volatile ("{%%%{a%}%||%%%}b}" : :); +}