nx_q4k_dot_simd2_lib.nx
buildroot/runtime/nx_q4k_dot_simd2_lib.nx
about
nx_q4k_dot_simd2_lib.nx -- the fused Q4_K SIMD dot with the COMPILER-EMITTED unpack (2026-09-02, LM4c).
Same algebra as nx_q4k_dot_simd (nx_q4k_dot_simd_lib): per super-block the eight i32 lanes accumulate
sum over all eight sub-blocks of (sc_sub*q)*col and ONE horizontal sum serves the super-block; the dmin
term is a scalar sum of m_sub times the precomputed sub-block activation sums. The ONLY difference is
HOW the 32 packed nibble bytes of a sub-block pair become 64 scaled i16 lanes: nx_q4k_dot_simd does it in
scalar NishiLang (four u64 reads, eight bit-spreads, eight 64-bit multiplies -- about 1.4 ops per weight,
the measured residual between the resident-Q4_K decode and the i16 cache route), this one calls
__q4k_unpack32s, one intrinsic that nx_cc emits as 14 AVX2 instructions (vpmovzxbw, vpsrlw, vpand,
vpmullw, vmovups). Bit-identical by construction: every lane ends up holding exactly (nibble * sc).
REQUIRES a compiler that knows __q4k_unpack32s (nx_types OP_Q4KUNPACK32S); a consumer built with an
older compiler fails to COMPILE, never silently falls back -- which is why this lives in its own lib and
nx_q4k_dot_simd_lib stays as the compiler-neutral twin until the toolchain is promoted on every host.
qbuf: 128 B caller scratch -- lo lanes at qbuf[0..31], hi lanes at qbuf[32..63] (i16), the layout
__i16x16_madd consumes directly (two 32-byte halves per group).
license_tier: ORIGINAL
dependencies 7 imports · 2 importers
imports: nx_syscalls.nxnx_tier.nxnx_le.nxnx_tensor.nxnx_gguf.nxnx_gguf_load.nxnx_q4k_dot_simd_lib.nx
imported by: nx_nofloat_q4k.nxnx_q4k_simd2_gate.nx
structs
| none |
consts
| 24 | const DS2_SUPER_BYTES: i64 = 144 |
| 25 | const DS2_SUPER_VALS: i64 = 256 |
| 26 | const DS2_SCALES_OFF: i64 = 4 |
| 27 | const DS2_QS_OFF: i64 = 16 |
| 28 | const DS2_GROUP_BYTES: i64 = 32 |
| 29 | const DS2_SUB_VALS: i64 = 32 |
| 30 | const DS2_SUBBLOCKS: i64 = 8 |
| 31 | const DS2_SC_HI_SHIFT: i64 = 16 // scpack = sc_lo | sc_hi << 16 |
| 32 | const DS2_QBUF_HI_OFF: i64 = 64 // hi lanes start 64 bytes into qbuf (32 i16) |
| 33 | const DS2_HALF_BYTES: i64 = 32 // one __i16x16_madd consumes 32 bytes (16 lanes) |
functions
| 37 | func nx_q4k_dot_simd2(buf: *u8, base_off: i64, n_blocks: i64, col_i16: *i64, qbuf: *i64, acc: *i64, sc_pre: *i64) -> i64 called by 2: _nq_mm_taskmain calls 5: _gguf_f16_to_q24nx_le_read_u16nx_le_read_u64nx_le_read_u32ds_hsum |