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 parentheses.
Operand Syntax
The representation of an operand syntax is as follows:
[<symbolic-name>] "<modifiers><constraints>" (expr)
int Add (int term1, int term2)
{
int sum;
_asm_ _volatile_
(
"add %0, %1, %2"
: "=r" (sum)
: "r" (term1), "r" (term2)
);
return sum;
}| C Function Implementation | Description |
|---|---|
Add() |
This function uses inline assembly to perform an addition
operation. Inputs two integer parameters,
term1 and term2, and
returns the result as a sum. |
add %0, %1, %2 |
This is the assembly instruction. It adds two integer parameters,
term1 and term2, and stores
the result in the output operand %0 (which
corresponds to sum in this case).
%1 and %2 are placeholders for
input operands, which are term1 and
term2 respectively. |
"=r" (sum) |
This is an output operand constraint. It tells the compiler that
the assembly instruction modifies the sum variable
and should be stored in a general-purpose register
(r). |
"=r" (term1), "=r" (term2) |
These are input operand constraints. They specify that
term1 and term2 should be
stored in registers (r) and are used as input to
the assembly instruction. |
You can omit any C function implementation by leaving it empty as shown by the following example.
int matrix [M][N];
void MatrixPreloadNow (int row)
{
_asm_ _volatile_
(
"lw t0, 0(%0)"
: //empty//
: "r" (%matrix [row] [0])
);
}The code in Example 2 loads the %0 data into temporary register,
t0. The assembly only provides the input constraint and
provides nothing to the output constraint. The pointer uses the data from
&matrix[row][0].
Operand References
The placeholders, %0, %1, etc., are known as
operand references or substitution operands. These placeholders represent input and
output operands within the inline asembly code. The numbers inside the placeholders
correspond to the sequence of operands specified in the constraints. The following
is the example of its usage.
int Add (int term1, int term2)
{
int sum;
_asm_ _volatile_
(
"add %0, %1, %2"
: "=r" (sum)
: "r" (term1), "r" (term2)
);
return sum;
}In the Add function from Example 3, %0 is used to represent the
output operands, which is the integer, sum. The %1
represents the input operand, term1 while %2
represents the input operand, term2.
Input Operands
The characteristics of input operands are as follows:
The input operands cannot have any constraint modifiers, but they can have any valid C expression if the type of the expression fits the register.
The C expression is evaluated just before any of the assembler instructions in the inline assembler statement and assigned to the constraint, for example a register.
Output Operands
The characteristics of output operands are as follows:
- Output operands must have “
=” as a constraint modifier and the C expression must be a l-value and specify writable location. For example,“=r”for a write-only general-purpose register. - The constraint is assigned to the evaluated C expression (as a l-value) immediately after the last assembler instruction in the inline assembler statement.
- Input operands are assumed to be consumed before output is produced.
- 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”.
The above characteristics ensure that the output operand is allocated to a different register from the input operands.
Input/Output Operands
The characteristics of input/output operands are as follows:
- 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 a l-value and specify a writable location.
- The location is read immediately before any assembler instructions, and is written right after the last assembler instruction.
Example of using a read-write operand:
int Double (int value)
{
_asm_ _volatile_
(
"add %0, %0, %0"
: "+r" (value)
);
return value;
}In Example 4, the input value is placed in a general-purpose
register. After the assembler statement, the result from the add
instruction is placed in the same register and return the result.
Operand Constraints
A constraint is a string full of letters, each of which describes one kind of operand that is permitted.
| Constraint Syntax | Description |
|---|---|
| A | An address that is held in a general-purpose register. |
| m | Memory. |
| r | Uses a general-purpose integer register for the expression: x1-x31 |
| i | A 32-bit integer. |
| l | An I-type 12-bit signed integer. |
| J | The constant integer zero. |
| K | A 5-bit unsigned integer for CSR instructions. |
| f | Uses a general-purpose floating-point register. |
| register_name | Uses this specific register for the expression. |
| digit |
|
Operand Constraint Modifiers
The constraint modifiers can be used together with a constraint to modify its meaning. The modifier should put in the first character of the constraint string. The following table lists the supported constraint modifiers:
| Modifier Syntax | Description |
|---|---|
+ |
Read-write operand. |
= |
Write-only operand: the previous value is discarded and replaced by new data. |
& |
This operand is an earlyclobber operand, which is written to before the instruction has processed all the input operands. |
Clobbered Resources
The characteristics of clobbered resources are as follows:
- An inline assembler statement can contain a list of clobbered resources.
- The clobbered registers that can be thrashed need to be specified in the assembly statement.
- By optimizing the GCC, you can specify or check for the clobbered registers.
- Any value that resides in a clobbered resource and that is needed after the inline assembly statement is reloaded.
Example of using clobbered resources:
int Add0x10000 (int term)
{
int sum;
_asm_ _volatile_
(
"lui s0, 0x10\n"
"add %0, %1, s0"
: "=r" (sum)
: "r" (term)
: "s0"
);
return sum;
}The following table lists the valid clobbered resources:
| Clobber | Description |
|---|---|
| x1-x3, a0-a7, s0-s11, t0-t6 | General-purpose integer registers. |
| f0-f31, fa0-fa7, fs0-fs11, ft0-ft11 | General-purpose floating-point registers. |
| Memory | To be used if the instructions modify any memory. This avoids keeping memory values cached in registers across the inline assembler statement. |
Example of using clobbered memory:
void Store (unsigned long*location, unsigned long value)
{
_asm_ _volatile_
(
"sw %1, 0(%0)"
:
: "=r" (location), "r" (value)
: "memory"
);
}