Extended Inline Assembly¶
Inline assembly has two contracts: the processor instructions and the compiler's model of their effects. Start with one register-only expression before adding memory or control flow.
Course examples on GitHub
Before you start¶
Complete NEON and scalar tails. Basic C++ is needed; use the separate-function interop lesson first if declarations or fixed-width types are unfamiliar.
Outcome: describe inputs, outputs and clobbers of a GCC extended-asm statement and test it at multiple optimization levels. Use a fresh directory on the Pi.
Describe every observable effect¶
The format is asm(template : outputs : inputs : clobbers). Operand constraints tell the compiler where values may live and whether an operand is read, written or both. Merely naming a register in a string does not inform the optimizer about an undeclared effect.
For the example below, "=r" declares a register output and "r" declares each input. %x[name] requests the 64-bit register spelling. The single ADD reads its inputs before writing the output, so an output sharing an input register is allowed.
Build a small checked example¶
Every run should print:
No flags clobber is needed for this ADD form because it does not set NZCV. No memory clobber is needed because the statement accesses no memory. Its result is used, so volatile is not required simply to force a useless operation to remain.
Know when this model stops being sufficient¶
| Change | New question |
|---|---|
| Read and overwrite one operand | Does it need a read/write constraint? |
| Write an output before reading all inputs | Is early-clobber required? |
| Change NZCV | Is the flags clobber declared? |
| Read or write pointed-to storage | Which memory effects are represented? |
| Call another function | Are stack, LR and all call effects modeled? |
| Communicate between threads/devices | Which language and hardware ordering rules apply? |
Do not hide a function call inside an otherwise register-only template. A compiler memory clobber is not a CPU memory barrier, and volatile is not a synchronization policy. See the GCC extended-asm documentation before extending the contract.
Prefer the simplest correct boundary¶
C++ a + b already expresses this unsigned operation. Inline asm here teaches constraints; it is not an optimization recommendation. For multiple blocks, calls or a reusable algorithm, a separate .S function with explicit tests is often easier to inspect.
If optimized builds disagree, investigate constraints and undefined behavior before disabling optimization. Passing three builds is useful evidence, not proof that an incomplete constraint set is valid.
Check your understanding¶
Why is adding volatile not a repair for a missing output or memory effect?
Compare your reasoning
Volatile does not declare the missing dependency or access. The compiler still needs an accurate operand/clobber contract to generate correct surrounding code.
Continue the course¶
Previous: NEON and Scalar Tails · Course roadmap · Next: Reading Specifications and Measuring