Inline assembly#
The asm
statement can be used to embed code written in assembly
inside a C or XC function. For example, the add instruction can be
written as follows:
asm("add %0, %1, %2" : "=r"(result) : "r"(a), "r"(b));
Colons separate the assembler template, the output operands and the
input operands. Commas separate operands within a group. Each operand is
described by an operand constraint string followed by an expression in
parentheses. The “r
” in the operand constraint string indicates that
the operand must be located in a register. The “=
” in the operand
constraint string indicates that the operand is written.
Each output operand expression must be an lvalue and must have “=
”
in its constraint.
The location of an operand may be referred to in the assembler template
using an escape sequence of the form %num
where num
is the
operand number. The escape sequence “%=
” can be used to emit a
number that is unique to each expansion of an asm
statement. This
can be useful for making local labels. To produce a literal “%
” you
must write “%%
”.
If code overwrites specific registers this can be described by using a third colon after the input operands, followed by the names of the clobbered registers as a comma-separated list of strings. For example:
asm ("get r11, id\n\tmov %0, r11"
: "=r"(result)
: /* no inputs */
: "r11");
The compiler ensures none of input or output operands are placed in clobbered registers.
If an asm
statement has output operands, the compiler assumes the statement
has no side effects apart from writing to the output operands. The compiler may
remove the asm
statement if the values written by the asm
statement are
unused. To mark an asm
statement as having side effects add the
volatile
keyword after asm
. For example:
asm volatile("in %0, res[%1]" : "=r"(result) : "r"(lock));
If the asm
statement accesses memory, add “memory
” to the list of
clobber registers. For example:
asm volatile("stw %0, dp[0]"
: /* no outputs */
: "r"(value));
This prevents the compiler caching memory values in registers around the
asm
statement.
The earlyclobber constraint modifier “&
” can be used to specify that
an output operand is modified before all input operands are consumed.
This prevents the compiler from placing the operand in the same register
as any of the input operands. For example:
asm("or %0, %1, %2\n"
"or %0, %0, %3\n"
: "=&r"(result)
: "r"(a), "r"(b), "r"(c));
Jumps from one asm
statement to another are not supported. asm
statements must not be used to modify the event enabled status of any resource.
An input operand can be tied to an output operand by specifying the number of the output operand in the input operand’s constraint. For example:
::
- asm(“zext %0, 8n”
: “=r”(result) : “0”(x));
Operands that are tied together will be allocated to the same register.