nx_hw_simd_caps.nx
buildroot/runtime/nx_hw_simd_caps.nx
about
nx_hw_simd_caps.nx -- runtime SIMD capability detection.
Reads /proc/cpuinfo and looks for vendor-specific flag tokens.
Sovereign: pure NishiLang, no libc, no /sys probe utilities, no
CPUID inline-asm dep. Works on every Linux arch the substrate
targets (x86_64, RV64, AArch64, etc.) -- /proc/cpuinfo is the
kernel's canonical CPU-feature reporting surface.
HISTORICAL NOTE: this module was the smoke that surfaced the
gp-relative relaxation bug fixed 2026-05-16. When 6 statics
fall within a single 4 KiB BSS window, the assembler optimizes
auipc+addi global-address sequences into addi(gp)+addi, but
our minimal crt0 doesn't initialize gp, so reads/writes
dereferenced garbage. Fixed in riscv.c by always emitting
`.option norelax` -- the bug class is now structurally
impossible regardless of static count. See docs/NISHILANG_CONCURRENCY.md
"Pitfalls" section for the diagnosis trail.
Why probe at runtime instead of compile-time:
- One binary can dispatch scalar / AVX2 / AVX-512 paths based
on the actual chip it runs on (vs N separate builds)
- Honest cardinal: refuse silent CPU-feature assumptions; ask
the kernel what it actually has
Use:
if nx_hw_has_avx512() == 1 { use_avx512_path() }
else if nx_hw_has_avx2() == 1 { use_avx2_path() }
else { use_scalar_path() }
Cost: ~4 KiB stack buffer + one sys_openat + one sys_read +
linear scan. Acceptable to call once at startup; cache in a
static for repeated checks.
Caches: once probed, results are stored in static i64 slots so
subsequent calls are zero-syscall.
dependencies 1 imports · 1 importers
imports: nx_syscalls.nx
imported by: nx_hw_simd_caps_test.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 45 | const NX_CPUINFO_BUF: i64 = 8192 |
functions
| 56 | func _nx_hw_read_cpuinfo(buf: *u8, cap: i64) -> i64 |
| 70 | func _nx_hw_has_token(buf: *u8, buf_len: i64, tok: *u8, tok_len: i64) -> i64 called by 1: _nx_hw_caps_init |
| 109 | func _nx_hw_tok_lit(buf: *u8, s_byte_0: i64, s_byte_1: i64, s_byte_2: i64, called by 1: _nx_hw_caps_init |
| 130 | func _nx_hw_caps_init() -> i64 |
| 161 | func nx_hw_has_avx2() -> i64 { _nx_hw_caps_init(); return NX_HW_HAS_AVX2 } |
| 162 | func nx_hw_has_avx512() -> i64 { _nx_hw_caps_init(); return NX_HW_HAS_AVX512 } |
| 163 | func nx_hw_has_sse4_2() -> i64 { _nx_hw_caps_init(); return NX_HW_HAS_SSE4_2 } |
| 164 | func nx_hw_has_rvv() -> i64 { _nx_hw_caps_init(); return NX_HW_HAS_RVV } |
| 165 | func nx_hw_has_neon() -> i64 { _nx_hw_caps_init(); return NX_HW_HAS_NEON } |
| 170 | func nx_hw_simd_i64x4_available() -> i64 |
| 189 | func _caps_smoke_run() -> i64 called by 1: main calls 5: nx_hw_has_avx2nx_hw_has_avx512nx_hw_has_rvvnx_hw_has_neonnx_hw_simd_i64x4_available |
| 198 | func main() -> i64 calls 1: _caps_smoke_run |