nx_nofloat_gemm.nx source
↩ module page · 41 lines · 2204 B
1// nx_nofloat_gemm.nx -- canonical sovereign INTEGER SIMD GEMM (vpmaddwd / __i16x16_madd):
2// EXACT + DETERMINISTIC + fast = the no-float compute lever every Nishi model rides. Pure funcs, no main.
3// Extracted from nx_nofloat_gemm_gate for debt-free reuse (gate + nx_gpu_bench both import this).
4// __i16x16_madd accumulates 16 signed-int16 products into an int32x8 vector (vpmaddwd + vpaddd, proven VEX);
5// integer add is associative -> bit-exact + deterministic (the no-float exceed axis, unlike float cuBLAS).
6// license_tier: ORIGINAL
7import "nx_syscalls.nx"
8
9func pack2(buf: *u8, idx: i64, val: i64) -> i64 { buf[idx*2]=(val) as u8; buf[idx*2+1]=(val>>8) as u8; return 0 }
10// Horizontal sum of an int32x8 accumulator. vpmaddwd lanes are SIGNED int32; `p[i]` on a *i32 SIGN-extends
11// since the 2026-07-10 sext compiler fix (i32 annotations mint sext=1 -> movslq loads). History: loads used
12// to ZERO-extend (no signedness in the IR), which turned negative lanes into ~4e9 garbage -- caught by the
13// nofloat W8A8 decode, worked around 2026-07-09 with a manual branchless sign-extend, then ROOT-FIXED in the
14// compiler + nxasm and the workaround removed. The gate's T5 negative-lane KAT pins this forever.
15func i32x8_hsum(acc: *u8) -> i64 { let p: *i32 = acc as *i32; var s: i64=0; var i: i64=0; while i<8 { s = s + (p[i] as i64); i=i+1 } return s }
16
17func scalar_imm(ai: *i64, bi: *i64, c: *i64, M: i64, N: i64, K: i64) -> i64 {
18 var i: i64=0
19 while i<M { var j: i64=0
20 while j<N { var acc: i64=0; var k: i64=0
21 while k<K { acc = acc + ai[i*K+k]*bi[j*K+k]; k=k+1 }
22 c[i*N+j]=acc; j=j+1 }
23 i=i+1 }
24 return 0
25}
26func simd_imm(a16: *u8, b16: *u8, c: *i64, acc: *u8, M: i64, N: i64, K: i64) -> i64 {
27 let ab: i64=a16 as i64
28 let bb: i64=b16 as i64
29 let z: *i64 = acc as *i64
30 var i: i64=0
31 while i<M { var j: i64=0
32 while j<N {
33 z[0]=0; z[1]=0; z[2]=0; z[3]=0
34 let ar: i64 = ab + i*K*2
35 let br: i64 = bb + j*K*2
36 var k: i64=0
37 while k<K { __i16x16_madd(acc, (ar+k*2) as *u8, (br+k*2) as *u8); k=k+16 }
38 c[i*N+j]=i32x8_hsum(acc); j=j+1 }
39 i=i+1 }
40 return 0
41}