10.3.2 Output and input operands

The inline assembly statement can optionally accept two lists of operand specifiers, the first for outputs and the second for inputs. These lists are used to pass values between the assembly code and the enclosing C/C++ function.

Syntax

Each list is a comma-separated list of operand specifiers. Each operand specifier can take one of the following two forms:

[<name>] "<constraint>" (<value>)
         "<constraint>" (<value>)

Where:

<name>
Is a name for referring to the operand in templates inside the inline assembly string. If the name for an operand is omitted, it must be referred to by number instead.
<constraint>
Is a string that tells the compiler how the value will be used in the assembly string, including:
  • For output operands, whether it is only written to, or both read from and written to. Also whether it can be allocated to the same register as an input operand. See 10.4.1 Constraint modifiers.
  • Whether to store the value in a register or memory, or whether it is a compile-time constant. See 10.4.2 Constraint codes.
<value>
Is a C/C++ value that the operand corresponds to. For output operands, this value must be a writable value.

Example

foo.c:
int saturating_add(int a, int b) {
	int result;
	__asm(
		  // The assembly string uses templates for the registers which hold output
		  // and input values. These will be replaced with the names of the
		  // registers that the compiler chooses to hold the output and input
		  // values.
		  
		  "qadd %0, %[lhs], %[rhs]"
		  
		  // The output operand, which corresponds to the "result" variable. This
		  // does not have a name assigned, so must be referred to in the assembly
		  // string by its number ("%0").
		  // The "=" character in the constraint string tells the compiler that the
		  // register chosen to hold the result does not need to have any
		  // particular value at the start of the inline assembly.
		  // The "r" character in the constraint tells the compiler that the value
		  // should be placed in a general-purpose register (r0-r12 or r14).
		  
		: "=r" (result)
		
		  // The two input operands also use the "r" character in their
		  // constraints, so the compiler will place them in general-purpose
		  // registers.
		  // These have names specified, which can be used to refer to them in
		  // the assembly string ("%[lhs]" and "%[rhs]").
		  
		: [lhs] "r" (a), [rhs] "r" (b)
	);
	
	return result;
}

Build this example with the following command:

armclang --target=arm-arm-none-eabi -march=armv7-a -O2 -c -S foo.c -o foo.s

The assembly language source file foo.s that is generated contains:

	.section	.text.saturating_add,"ax",%progbits
	.hidden saturating_add			@ -- Begin function saturating_add
	.globl  saturating_add
    .p2align    2
    .type   saturating_add,%function
    .code   32						@ @saturating_add
saturating_add:
	.fnstart
@ %bb.0:							@ %entry
	@APP
	qadd r0,r0,r1
	@NO_APP
	bx lr
.Lfunc_end0:
	.size saturating_add, .Lfunc_end0-saturating_add
	.cantunwind
	.fnend

In this example:

  • The compiler places the C function saturating_add() in a section that is called .text.saturating_add.
  • Within the body of the function, the compiler expands the inline assembly statement into the qadd r0, r0, r1 instruction between the comments @APP and @NO_APP. In -S output, the compiler always places code that it expands from inline assembly statements within a function between a pair of @APP and @NO_APP comments.
  • The compiler uses the general-purpose register R0 for:
    • The int a parameter of the saturating_add() function.
    • The inline assembly input operand %[lhs].
    • The inline assembly output operand %0.
    • The return value of the saturating_add() function.
  • The compiler uses the general-purpose register R1 for:
    • The int b parameter of the saturating_add() function.
    • The inline assembly input operand %[rhs].
Non-ConfidentialPDF file icon PDF versionDUI0774J
Copyright © 2014–2017, 2019 Arm Limited or its affiliates. All rights reserved.