nx_q8_0_to_f32.nx source
↩ module page · 54 lines · 1782 B
1// nx_q8_0_to_f32.nx -- bits-up Q8_0 dequantization to IEEE 754 binary32.
2//
3// Q8_0 block layout (per ggml v3 spec; clean-room from public docs):
4// 34 bytes per block of 32 values:
5// bytes [0..2] d (f16 scale)
6// bytes [2..34] qs (32 signed i8 quants)
7//
8// Dequant: value_f32 = d_f32 * (i8)qs[i]
9//
10// genealogy_id: ggml_q8_0_canon
11// lineage_id: substrate_q8_0_to_f32_v1
12
13import "nx_syscalls.nx"
14import "nx_tier.nx"
15import "nx_le.nx"
16import "nx_f32.nx"
17import "nx_f32_cvt.nx"
18
19const NX_Q8_0_OK: nx_int = 0
20const NX_Q8_0_VPB: i64 = 32
21const NX_Q8_0_BPB: i64 = 34
22
23func _nx_q8_0_block_to_f32(buf: *u8, base_off: i64, take: i64,
24 out_f32: *i64) -> nx_int {
25 let d_f16: i64 = nx_le_read_u16(buf, base_off)
26 let d_f32: i64 = nx_f16_to_f32(d_f16)
27 let qs_off: i64 = base_off + 2
28
29 var i: i64 = 0
30 while i < take {
31 let qs_u8: i64 = nx_le_read_u8(buf, qs_off + i)
32 var qs_i: i64 = qs_u8
33 if qs_i >= 128 { qs_i = qs_i - 256 }
34 out_f32[i] = __f32_mul(d_f32, __f32_from_i64(qs_i)) // HW cvtsi2ss+mulss (2026-07-08); bit-exact for int8*scale
35 i = i + 1
36 }
37 return NX_Q8_0_OK
38}
39
40func nx_q8_0_to_f32(buf: *u8, base_off: i64, n_values: i64,
41 out_f32: *i64) -> nx_int {
42 let n_blocks: i64 = (n_values + NX_Q8_0_VPB - 1) / NX_Q8_0_VPB
43 var b: i64 = 0
44 while b < n_blocks {
45 let block_off: i64 = base_off + b * NX_Q8_0_BPB
46 let block_n: i64 = n_values - b * NX_Q8_0_VPB
47 var take: i64 = block_n
48 if take > NX_Q8_0_VPB { take = NX_Q8_0_VPB }
49 _nx_q8_0_block_to_f32(buf, block_off, take,
50 ((out_f32 as i64) + b * NX_Q8_0_VPB * 8) as *i64)
51 b = b + 1
52 }
53 return NX_Q8_0_OK
54}