Inline Assembly
Zynx supports inline assembly through the asm keyword, following the GCC/Clang extended assembly format.
Use inline assembly only for narrow low-level cases (for example, CPU feature instructions, special register access, or hand-tuned leaf paths). Prefer normal Zynx/C code when possible.
Syntax
asm [volatile] ( template [ : outputs [ : inputs [ : clobbers ] ] ] );
volatile: Prevents the compiler from optimizing away the block.template: A string literal containing the assembly code. Operands are referenced via%0,%1, etc.outputs/inputs: Comma-separated list of operand constraints.clobbers: A list of registers or memory modified by the assembly code.
Operands
Connect Zynx variables to assembly instructions:
[ "[" name "]" ] constraint ( expression )
name: Optional symbolic name for the operand.constraint: A string literal specifying the storage class (e.g.,"r"for register,"m"for memory).expression: The Zynx variable to bind.
Clobbers
Instruct the compiler to save and restore registers or memory. Common clobbers include "memory" and "cc".
Platform and Toolchain Notes
- Inline assembly support depends on the backend C compiler and target architecture.
- Constraint letters and accepted templates are backend-defined (Clang/GCC style), not Zynx-specific.
- Cross-target assembly must match the selected target ABI and instruction set.
- Windows targets may require different syntax/constraints depending on toolchain behavior.
Common Pitfalls
- Missing
"memory"clobber when the assembly reads/writes memory not listed as operands can cause incorrect reordering. - Missing
"cc"clobber when condition flags are modified can break surrounding branch logic. - Omitting
volatilefor side-effect-only instructions may let the optimizer remove the block. - Using wrong constraints (for example forcing register when memory is required) can fail compilation or miscompile.
- Clobbering callee-saved registers manually is unsafe unless fully modeled through constraints/clobbers.
Examples
Basic
asm("nop");
Arithmetic
fn add(a: i32, b: i32) -> i32 {
let result: i32 = 0;
asm("add %2, %0"
: "=r"(result) // Output %0
: "0"(a), "r"(b) // Input %1 (tied to %0), Input %2
: "cc"
);
return result;
}
Volatile Operation
asm volatile ("cli"); // Disable interrupts
Memory Barrier Example
asm volatile ("" ::: "memory");
This empty template acts as a compiler barrier for memory reordering.