clang/llvm support for %= in inline assembly

from https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

Under certain circumstances, GCC may duplicate (or remove duplicates of) your assembly code when optimizing. This can lead to unexpected duplicate symbol errors during compilation if your asm code defines symbols or labels. Using ‘%=’ (see AssemblerTemplate) may help resolve this problem.

‘%=’
Outputs a number that is unique to each instance of the asm statement in the entire compilation. This option is useful when creating local labels and referring to them multiple times in a single template that generates multiple assembler instructions.

I tried to implement %= in my front-end but I ran into this problem with the optimizer. So in order to have this feature, LLVM would need to support it in the IR language.

As far as I can tell, Clang does not support this feature. Is it a reasonable feature request?

Regards,
Andrew

I think we may already support it. At least that’s the implication from the post-commit thread of r288093, in particular this reply from Reid https://www.mail-archive.com/cfe-commits@lists.llvm.org/msg43592.html

Do you have a test case?

– Sean Silva

I encountered this issue of unique asm label names just now, in 216771 – graphics/rawstudio: fails to build with clang 4.0 . A very simple test case is this:

  void foo(void)
  {
    asm volatile(
      "named_label:\n"
      "jnz named_label\n"
    );
  }

  void bar(void)
  {
    foo();
  }

Compiling this with any form of optimization gives an error, because clang is attempting to inline foo() into bar(), thereby cloning the inline asm part:

  $ clang -O -c test.c
  test.c:4:5: error: invalid symbol redefinition
      "named_label:\n"
      ^
  <inline asm>:1:2: note: instantiated into assembly here
          named_label:
          ^
  1 error generated.

This error is very confusing to the end user, IMHO. Either clang should uniq-ify each of these labels automatically, when inlining functions, or it should give you advice on how to use anonymous asm labels, or %= macros.

Appending %= to the label name only works if you append at least one ':' to the asm statement, otherwise it isn't seen as a so-called "assembler template", apparently:

  void foo(void)
  {
    asm volatile(
      "named_label_%=:\n"
      "jnz named_label_%=\n"
      :
    );
  }

  void bar(void)
  {
    foo();
  }

Resulting in:

  $ clang -O -S test.c -o -
          .text
          .file "test.c"
          .globl foo
          .p2align 4, 0x90
          .type foo,@function
  foo: # @foo
  # BB#0: # %entry
          pushl %ebp
          movl %esp, %ebp
          #APP
  named_label_0:
          jne named_label_0

          #NO_APP
          popl %ebp
          retl
  .Lfunc_end0:
          .size foo, .Lfunc_end0-foo

          .globl bar
          .p2align 4, 0x90
          .type bar,@function
  bar: # @bar
  # BB#0: # %entry
          pushl %ebp
          movl %esp, %ebp
          #APP
  named_label_1:
          jne named_label_1

          #NO_APP
          popl %ebp
          retl
  .Lfunc_end1:
          .size bar, .Lfunc_end1-bar

This is with clang 4.0.0 from the release_40 branch. I have no idea when the %= support was added.

-Dimitry

Aha, ok, perfect, this results in LLVM IR:

  tail call void asm sideeffect "named_label_${:uid}:\0Ajnz
named_label_${:uid}\0A", "~{dirflag},~{fpsr},~{flags}"() #2, !dbg !20,
!srcloc !25

So LLVM IR does in fact already support it, and my use case is solved.
However, it is undocumented in http://llvm.org/docs/LangRef.html. Might be
night to add there for future developers.

I documented this in r294204.