Nitpick Inline Assembly Specification
Nitpick provides direct, low-level access to the LLVM
inline assembly backend via two powerful compiler built-ins:
asm!! and asm!!!.
These built-ins act as ultimate escape hatches for performance-critical inner loops, SIMD optimizations, and direct hardware interaction.
1. Syntax and Structure
Both built-ins use a variadic generic signature that maps cleanly to LLVM’s inline assembly constructs.
asm!!<T>(string:arch, string:asm_code, string:constraints, args...);
asm!!!<T>(string:arch, string:asm_code, string:constraints, args...);
T: The expected return type of the assembly block.arch: The target architecture string (e.g.,"x86_64","aarch64").asm_code: The raw assembly instructions.constraints: The standard LLVM register constraint string (e.g.,"=r,r,r"or"=a,a,b").args...: The variadic Nitpick variables that feed into the assembly constraints.
2. Safety Tiers
Nitpick splits inline assembly into two tiers of safety regarding error handling.
2.1 The Supervised Tier:
asm!!<T>
This variant enforces Nitpick’s standard error
propagation by wrapping the return value in a
Result<T>. By convention, if the assembly
block leaves a negative integer in the primary output
register, Nitpick interprets it as an error code, mapping it
into the tbb error field of the
Result<T>.
// Safe wrapping: Must unwrap with raw, drop, or check .is_error
Result<int32>:res = asm!!<int32>("x86_64", "add %eax, %ebx", "=r,r,r", x, y);
int32:val = raw res;
2.2 The Raw Tier:
asm!!!<T>
This variant is completely unchecked. It returns a
bare T, totally bypassing the
Result<T> wrapper. It assumes the
operation cannot fail or that the developer will manually
check the output value.
// Raw return: no `raw` keyword or Result handling needed
int32:res = asm!!!<int32>("x86_64", "add %eax, %ebx", "=r,r,r", x, y);
3. Compiler Integration
The Nitpick compiler passes the assembly strings and
constraints directly to the LLVM backend.
Therefore, any constraint violations (e.g.,
couldn't allocate output register for constraint 'a')
will be caught and reported natively during the LLVM code
generation phase.
[!NOTE] By default, LLVM (and therefore Nitpick) uses AT&T syntax for x86/x86_64 inline assembly. Ensure your assembly strings follow AT&T register and instruction formatting (e.g.,
add %eax, %ebxinstead of Intel’sadd ebx, eax).
4. JIT SIMD Instruction Emission (v0.80.3)
The JIT engine provides direct SIMD instruction emission
for runtime-generated vectorized code. These are not inline
assembly — they are assembler API calls that emit machine
code into a wildx code buffer.
4.1 CPUID Runtime Detection
JitCpuFeatures npk_jit_detect_cpu(void); // Returns cached feature flags
bool npk_jit_has_avx2(void); // AVX2 available?
bool npk_jit_has_sse42(void); // SSE4.2 available?
bool npk_jit_has_neon(void); // NEON available? (AArch64 only)JitCpuFeatures fields: sse2,
sse3, ssse3, sse41,
sse42, avx, avx2,
avx512f.
4.2 x86_64 SSE2 Instructions (128-bit, XMM)
| Function | Instruction | Description |
|---|---|---|
npk_asm_movdqu_xmm_mem |
MOVDQU | Unaligned 128-bit load |
npk_asm_movdqu_mem_xmm |
MOVDQU | Unaligned 128-bit store |
npk_asm_movdqa_xmm_mem |
MOVDQA | Aligned 128-bit load |
npk_asm_movdqa_mem_xmm |
MOVDQA | Aligned 128-bit store |
npk_asm_paddd |
PADDD | 4×int32 add |
npk_asm_paddw |
PADDW | 8×int16 add |
npk_asm_paddb |
PADDB | 16×int8 add |
npk_asm_psubd |
PSUBD | 4×int32 subtract |
npk_asm_psubw |
PSUBW | 8×int16 subtract |
npk_asm_pmulld |
PMULLD | 4×int32 multiply |
npk_asm_pcmpeqd |
PCMPEQD | Lane-wise compare equal |
npk_asm_pand |
PAND | Bitwise AND |
npk_asm_por |
POR | Bitwise OR |
npk_asm_pxor |
PXOR | Bitwise XOR |
npk_asm_pshufb |
PSHUFB | Byte shuffle |
4.3 x86_64 AVX2 Instructions (256-bit, YMM, VEX-encoded)
| Function | Instruction | Description |
|---|---|---|
npk_asm_vmovdqu_ymm_mem |
VMOVDQU | 256-bit unaligned load |
npk_asm_vmovdqu_mem_ymm |
VMOVDQU | 256-bit unaligned store |
npk_asm_vpaddd_ymm |
VPADDD | 8×int32 add (3-operand) |
npk_asm_vpsubd_ymm |
VPSUBD | 8×int32 subtract (3-operand) |
npk_asm_vpbroadcastd |
VPBROADCASTD | Broadcast int32 to all 8 lanes |
4.4 AArch64 NEON/AdvSIMD Instructions (128-bit, V registers)
| Function | Instruction | Description |
|---|---|---|
a64_emit_ld1_4s |
LD1 {Vt.4S},[Xn] | 128-bit vector load |
a64_emit_st1_4s |
ST1 {Vt.4S},[Xn] | 128-bit vector store |
a64_emit_add_vec_4s |
ADD Vd.4S | 4×int32 add |
a64_emit_sub_vec_4s |
SUB Vd.4S | 4×int32 subtract |
a64_emit_mul_vec_4s |
MUL Vd.4S | 4×int32 multiply |
a64_emit_dup_4s_gpr |
DUP Vd.4S,Wn | Broadcast GPR to all lanes |
a64_emit_and_vec |
AND Vd.16B | Bitwise AND |
a64_emit_orr_vec |
ORR Vd.16B | Bitwise OR |
a64_emit_eor_vec |
EOR Vd.16B | Bitwise XOR |
a64_emit_cmeq_4s |
CMEQ Vd.4S | Lane-wise compare equal |