[LLVMdev] [RFC] MS-style inline assembly

Chad Rosier mcrosier at apple.com
Mon Aug 6 11:14:27 PDT 2012


All,
The purpose of this email is to open a discussion on the design and
implementation of support for  Microsoft-style inline assembly in clang.  The
majority of the work will be done in clang, but I'm CC'ing both dev lists to get
the most exposure possible.  There are _many_ open questions and the
forthcoming description is likely to be obscure in many place (at times this
is on purpose, while other times you'll just have to bear with me), but hopefully
this will be a good starting point.

Clang currently supports the GNU-style inline assembly of the form:

  asm ( assembler template
           : output operands                     /* optional */
           : input operands                        /* optional */
           : list of clobbered registers      /* optional */
           );

When writing extended assembly, the user specifies the output operands, input
operands, constraints and a list of clobbered registers.  This largely simplifies the
job of the compiler, but can be prone to user error.

Conversely, Microsoft-style inline assembly uses ordinary asm text without 
explicitly defining output operands, input operands, constraints and clobbered
registers; the compiler is responsible for discovering this information.

1. How is clang going to discover the input operands, output operands, 
constraints, and clobbered registers?

Support for parsing the Intel asm dialect exists in the X86AsmParser.  Ideally,
all the necessary information can be provided to us by the MC layer.  Thus,
given a valid asm statement that does not reference variable names, function
names, or labels

void foo(void) {
  __asm mov eax, eax
}

the AsmParser can match the asm statement to a MCInst.  From the MCInst we can
obtain the MCInstrDesc information, which is used to determine the number of 
operands, uses, defs and constraints of each asm statement.  This information is
also helpful for semantic checking.  Asm statements that reference variables
require special handling, however.

unsigned foo(void) {
  unsigned i = 1, j;
  __asm mov eax, i
  __asm mov j, eax
  return j;
}

In the above example, the two asm statments are not valid assembly.
Thus, the AsmParser cannot parse these statements without some modifications.

Type information, provided by Sema::LookupName(), is used to guess the
appropriate register class for patching the asm statements.  For example, the first
asm statement could be modified as:

 mov eax, i -> mov eax, ecx

Here we're somewhat guessing that ecx is valid.  This isn't going to work in
all cases, so we may need to probe the AsmParser with several alternatives.
It is yet to be determined how we handle the case of multiple matches.

3. Which syntax, AT&T or Intel, should be passed to the backend?

The approach taken by llvm-gcc is to translate the Intel syntax into the AT&T
syntax in the front-end.  The advantage here is that the backend requires 
minimal changes.  However, I will argue that the asm should remain in the
Intel syntax and the backend should be modified to handle this.  This has a number
of advantage: (1) it removes a great deal of complex textual processing from the
frontend, (2) is likely to provide better diagnostic information, and (3) 
emitting the Intel syntax is what the user expects.  The backend will need to
be taught the right syntax for operands (i.e. the address of a stack variable
is "DWORD PTR [8+ESP]" rather than "8(%esp)"), however.

4. How do we distinguish the assembly dialect at the IR level?

One approach would be wrap the asm text passed to the backend with .intel_syntax
and .att_syntax.  E.g.,

  call void asm sideeffect ".intel_syntax\n\tnop\n\t.att_syntax", "~{dirflag},~{fpsr},~{flags}"() nounwind

Besides being rather hackish, this isn't likely going to work.  Based on feedback
from other internal developers, I would like to propose a small IR extension.
Specifically, I would like to add a function attribute to inline asm calls that
indicates the syntax in which the asm is written.

E.g.,

  call void asm sideeffect "nop\n\t", "~{dirflag},~{fpsr},~{flags}"() nounwind iasyntaxatt

Notice the addition of the iasyntaxatt keyword.  This is used by the AsmPrinter
to determine the correct asm variant.  I've implemented this change and would be
happy to send it to the commits list for review.  However, the backend doesn't currently
use this information so I don't think it would need to be committed at this time.  I just
wanted to give everyone an idea of what I was thinking.

5. How should the inline asm be represented in the AST?

This is largely an open question and I'm still in the process of familiarize
myself with the frontend.  Doing this in a sane way is going to be critical for
providing good diagnostic information.

6. Additional comments:

One additional goal of this project is to implement support for MS-style inline
assembly in a target-independent way.  Thus, we should be able to use the same
inline assembly syntax for other architectures (e.g., ARM).

Hopefully, this gives everyone a _very_ high level view of the direction I would like to
take for implementing MS-style inline assembly.  You feedback and suggestions
are _very_ welcome.

 Chad



More information about the llvm-dev mailing list