code wiki / (root) / nx_q8_0_from_q5_0.nx

nx_q8_0_from_q5_0.nx source

↩ module page · 58 lines · 2579 B

1// nx_q8_0_from_q5_0.nx -- re-quantize a Q5_0 tensor to Q8_0 IN MEMORY. 2// 3// THE KEY MOVE (2026-07-08): Q5_0's nibble+qh unpack is what made a per-token 4// Q5_0 SIMD dequant-dot COMPUTE-bound (2x slower). But Q5_0 -> Q8_0 is EXACT 5// (the 5-bit values -16..15 fit in int8, same per-block f16 scale d), so we 6// repack ONCE AT LOAD -- amortizing the unpack -- and the forward then runs 7// the TRIVIAL Q8_0 SIMD dequant-dot (__f32_i8dot32, PROVEN 10.2x) per token. 8// The unpack uses the blessed __q5_unpack32 intrinsic itself. 9// 10// Q5_0 block (22B): d(f16) + qh(u32) + qs(16B). Q8_0 block (34B): d(f16) + 11// 32 int8. Repack: copy d; __q5_unpack32(qh+qs) -> the 32 int8 = q5-16. 12// lineage_id: q8_0_from_q5_0_v1 13import "nx_syscalls.nx" 14import "nx_le.nx" 15import "nx_q5_0_to_f32.nx" 16import "nx_q8_0_to_f32.nx" 17 18static g_q5repack_consts: i64 19func _q5repack_consts() -> *u8 { 20 if g_q5repack_consts == 0 { 21 let cc: *u8 = sys_mmap(80) 22 var i: i64 = 0 23 while i < 16 { cc[i] = 0x0F as u8; i = i + 1 } // c_0F 24 i = 0 25 while i < 8 { cc[16+i] = 0 as u8; i = i + 1 } 26 while i < 16 { cc[16+i] = 1 as u8; i = i + 1 } // pshuf_lo 27 i = 0 28 while i < 8 { cc[32+i] = 2 as u8; i = i + 1 } 29 while i < 16 { cc[32+i] = 3 as u8; i = i + 1 } // pshuf_hi 30 i = 0 31 while i < 8 { cc[48+i] = (1 << i) as u8; cc[48+8+i] = (1 << i) as u8; i = i + 1 } // bitmask 32 i = 0 33 while i < 16 { cc[64+i] = 0x10 as u8; i = i + 1 } // c_10 34 g_q5repack_consts = cc as i64 35 } 36 return g_q5repack_consts as *u8 37} 38 39// Repack n_values (must be a multiple of 32) of Q5_0 at q5buf+q5off into 40// contiguous Q8_0 blocks at out_q8. Returns 0. 41func nx_q8_0_from_q5_0(q5buf: *u8, q5off: i64, n_values: i64, out_q8: *u8) -> i64 { 42 let consts: *u8 = _q5repack_consts() 43 let nblk: i64 = (n_values + NX_Q5_0_VPB - 1) / NX_Q5_0_VPB 44 let q5pb: i64 = q5buf as i64 45 let q8pb: i64 = out_q8 as i64 46 var b: i64 = 0 47 while b < nblk { 48 let q5boff: i64 = q5off + b * NX_Q5_0_BPB // 22 B/block 49 let q8boff: i64 = b * NX_Q8_0_BPB // 34 B/block 50 out_q8[q8boff + 0] = q5buf[q5boff + 0] // copy d (f16) lo 51 out_q8[q8boff + 1] = q5buf[q5boff + 1] // copy d (f16) hi 52 // qh at q5boff+2, qs at q5boff+6 are contiguous -> qhqs = q5boff+2. 53 // int8 output at q8boff+2 (the 32 quants). 54 __q5_unpack32((q5pb + q5boff + 2) as *u8, (q8pb + q8boff + 2) as *u8, consts) 55 b = b + 1 56 } 57 return 0 58}