Reference information for inline assembler
Theasm extended keyword and its aliases __asm and __asm__ all insert assembler instructions. However, when you compile C source code, the asm keyword is not available when the option ‑‑strict is used. The __asm and __asm__ keywords are always available.
Syntax
The syntax of an inline assembler statement is (similar to the one used by GNU GCC):
asm [volatile](string[assembler-interface])
A string can contain one or more operations, separated by \n. Each operation can be a valid assembler instruction or a data definition assembler directive prefixed by an optional label. There can be no whitespace before the label and it must be followed by :.
For example:
asm("label:nop\n"
"j label");Note
Any labels you define in the inline assembler statement will be local to that statement. You can use this for loops or conditional code.
If you define a label in an inline assembler statement using two colons—for example, "label:: nop\n"—instead of one, the label will be public, not only in the inline assembler statement, but in the module as well. This feature is intended for testing only.
An assembler statement without declared side-effects will be treated as a volatile assembler statement, which means it cannot be optimized at all. The compiler will issue a remark for such an assembler statement.
assembler-interface is:
: comma-separated list of output operands /* optional */ : comma-separated list of input operands /* optional */ : comma-separated list of clobbered resources /* optional */
Operands
An inline assembler statement can have one input and one output comma-separated list of operands. Each operand consists of an optional symbolic name in brackets, a quoted constraint, followed by a C expression in parentheses.
Syntax of operands
[[symbolic-name]] "[modifiers]constraint" (expr)
For example:
int Add(int term1, int term2)
{
int sum;
asm("add %0,%1,%2"
: "=r"(sum)
: "r" (term1), "r" (term2));
return sum;
}In this example, the assembler instruction uses one output operand, sum, two input operands, term1 and term2, and no clobbered resources.
It is possible to omit any list by leaving it empty. For example:
int matrix[M][N]; void MatrixPreloadRow(int row) { asm volatile ("lw zero, 0(%0)" : : "r" (&matrix[row][0])); }
Operand constraints
The operand constraints define how to pass an operand between inline assembler code and the surrounding C or C++ code.
Constraint | Description |
|---|---|
| The address of an object |
| Uses a general purpose floating-point register |
| A 32-bit integer |
| A 12-bit signed integer |
| The constant zero |
| A 5-bit unsigned integer |
| Memory |
| Uses a general purpose integer register for the expression: |
| Uses this specific register for the expression |
| The input must be in the same location as the output operand |
Constraint | Description |
|---|
Constraint modifiers
Constraint modifiers can be used together with a constraint to modify its meaning. This table lists the supported constraint modifiers:
Modifier | Description |
|---|---|
= | Write-only operand |
+ | Read-write operand |
& | Early clobber output operand which is written to before the instruction has processed all the input operands. |
Referring to operands
Assembler instructions refer to operands by prefixing their order number with %. The first operand has order number 0 and is referred to by %0.
If the operand has a symbolic name, you can refer to it using the syntax %[operand.name]. Symbolic operand names are in a separate namespace from C/C++ code and can be the same as a C/C++ variable names. Each operand name must however be unique in each assembler statement. For example:
int Add(int term1, int term2)
{
int sum;
asm("add %[Rd],%[Rn],%[Rm]"
: [Rd]"=r"(sum)
: [Rn]"r" (term1), [Rm]"r" (term2));
return sum;
}Input operands
Input operands cannot have any constraint modifiers, but they can have any valid C expression as long as the type of the expression fits the register.
The C expression will be evaluated just before any of the assembler instructions in the inline assembler statement and assigned to the constraint, for example, a register.
Output operands
Output operands must have = as a constraint modifier and the C expression must be an l-value and specify a writable location. For example, =r for a write-only general purpose register. The constraint will be assigned to the evaluated C expression (as an l-value) immediately after the last assembler instruction in the inline assembler statement. Input operands are assumed to be consumed before output is produced and the compiler may use the same register for an input and output operand. To prohibit this, prefix the output constraint with & to make it an early clobber resource, for example, =&r. This will ensure that the output operand will be allocated in a different register than the input operands.
Input/output operands
An operand that should be used both for input and output must be listed as an output operand and have the + modifier. The C expression must be an l-value and specify a writable location. The location will be read immediately before any assembler instructions and it will be written to right after the last assembler instruction.
This is an example of using a read-write operand:
int Double(int value)
{
asm("add %0,%0,%0" : "+r"(value));
return value;
}In the example above, the input value for value will be placed in a general purpose register. After the assembler statement, the result from the ADD instruction will be placed in the same register.
Clobbered resources
An inline assembler statement can have a list of clobbered resources.
"resource1", "resource2", ...
Specify clobbered resources to inform the compiler about which resources the inline assembler statement destroys. Any value that resides in a clobbered resource and that is needed after the inline assembler statement will be reloaded.
Clobbered resources will not be used as input or output operands.
This is an example of how to use clobbered resources:
int Add0x10000(int term)
{
int sum;
asm("lui s0, 0x10\n"
"add %0, %1, s0"
: "=r"(sum)
: "r" (term)
: "s0");
return sum;
}This table lists valid clobbered resources:
Clobber | Description |
|---|---|
| General purpose integer registers |
| General purpose floating-point registers |
| To be used if the instructions modify any memory. This will avoid keeping memory values cached in registers across the inline assembler statement. |
Operand modifiers
An operand modifier is a single letter between the % and the operand number, which is used for transforming the operand.
In the example below, an instruction like ‘and a0, a0, zero’ is generated if the function is inlined, and 0 is passed as the second argument to Mask:
int Mask(int term1, int term2)
{
int sum;
asm("and %0, %1, %z2"
: "=r"(sum)
: "r" (term1), "r" (term2));
return sum;
}This table describes the transformation performed by each valid modifier:
Modifier | Description |
|---|---|
| If the input value is equal to the integer constant 0, the register |