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)

Example 1:
int Add (int term1, int term2)
{
     int sum;
     _asm_ _volatile_
     (
     "add %0, %1, %2"
     : "=r" (sum)
     : "r" (term1), "r" (term2)
     );
     return sum;
}
Table 1. Explanation of Example 1
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.

Example 2:
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.

Example 3:
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:

Example 4:
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.

Table 2. Inline Assembler Operand Constraints
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
  • The input must be in the same location as the output operand digit.
  • If a digit is used together with letters within the same alternative, then the digit should come last.
Note: For the full lists of operand constraints, refer to the GNU GCC documentation.

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:

Table 3. 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.
Note: The compiler can only handle one commutative (constraint) pair in an assembly. The compiler may fail if you use more than one commutative pair.

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.
Note: Clobbered resources is used as input or output operands.

Example of using clobbered resources:

Example 5:
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:

Table 4. Lists of 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:

Example 6:
void Store (unsigned long*location, unsigned long value)
{
     _asm_ _volatile_
     (
     "sw %1, 0(%0)"
     :
     : "=r" (location), "r" (value)
     : "memory"
     );
}