code wiki / _hdl_build / nx_simd_isa_test.nx

nx_simd_isa_test.nx source

↩ module page · 73 lines · 3531 B

1// nx_simd_isa_test.nx -- the vectorized FMA kernel as real vector MACHINE CODE, 2// proven by EXECUTION on the sovereign SIMD emulator. Memory image holds a|b|d|c 3// (N each). For each block the vectorizer EMITS 6 vector instructions (3 VLOAD, 4// VMUL, VADD, VSTORE) and sv_run executes them; the resulting c region must equal 5// the scalar c, 1:1, including the scalar tail. Known answer: arrays identical AND 6// vector instructions << scalar ops -> exit 0. 7 8import "nx_simd_isa.nx" 9 10func sx_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 11func sx_num(v: i64) -> i64 { 12 let b: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m } 13 let t: *u8 = sys_mmap(28); var k: i64 = 0 14 if m == 0 { t[0] = 48; k = 1 } 15 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 } 16 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 17 sys_write(1, b, k); return 0 18} 19 20func main() -> i64 { 21 sx_puts("=== vectorized FMA as vector MACHINE CODE, proven on the SIMD emulator ===\n" as *u8) 22 let N: i64 = 100 // tail of 4 (not a multiple of SV_W=8) 23 let mem: *i64 = sys_mmap(8 * 4 * (N + 16)) as *i64 // a[0..N) b[N..2N) d[2N..3N) c[3N..4N) 24 let cs: *i64 = sys_mmap(8 * (N + 16)) as *i64 // scalar reference c 25 26 var s: i64 = 88172645463325252 27 var i: i64 = 0 28 while i < N { 29 s = s * 6364136223846793005 + 1442695040888963407; mem[i] = (s >> 40) & 0xFFFF // a 30 s = s * 6364136223846793005 + 1442695040888963407; mem[N + i] = (s >> 40) & 0xFFFF // b 31 s = s * 6364136223846793005 + 1442695040888963407; mem[2 * N + i] = (s >> 40) & 0xFFFF // d 32 i = i + 1 33 } 34 // scalar reference: c[i] = a[i]*b[i] + d[i] 35 i = 0 36 while i < N { cs[i] = mem[i] * mem[N + i] + mem[2 * N + i]; i = i + 1 } 37 38 // VECTOR machine code, per block, executed on the emulator. 39 let vregs: *i64 = sys_mmap(8 * 8 * SV_W) as *i64 40 let prog: *i64 = sys_mmap(8 * 2 * 16) as *i64 41 var vinstr: i64 = 0 42 i = 0 43 while i + SV_W <= N { 44 var p: i64 = 0 45 p = sv_emit(prog, p, SVOP_VLOAD, 0, 0, 0, i) // v0 = a[i..] 46 p = sv_emit(prog, p, SVOP_VLOAD, 1, 0, 0, N + i) // v1 = b[i..] 47 p = sv_emit(prog, p, SVOP_VLOAD, 2, 0, 0, 2 * N + i) // v2 = d[i..] 48 p = sv_emit(prog, p, SVOP_VMUL, 3, 0, 1, 0) // v3 = v0*v1 49 p = sv_emit(prog, p, SVOP_VADD, 3, 3, 2, 0) // v3 = v3+v2 50 p = sv_emit(prog, p, SVOP_VSTORE, 0, 3, 0, 3 * N + i) // c[i..] = v3 (va=3) 51 vinstr = vinstr + sv_run(prog, p, vregs, mem) 52 i = i + SV_W 53 } 54 // scalar tail 55 while i < N { mem[3 * N + i] = mem[i] * mem[N + i] + mem[2 * N + i]; i = i + 1 } 56 57 // 1:1 -- the vector-computed c region must equal the scalar reference. 58 var mism: i64 = 0 59 i = 0 60 while i < N { if mem[3 * N + i] != cs[i] { mism = mism + 1 } i = i + 1 } 61 62 let scalar_ops: i64 = 2 * N 63 sx_puts(" elements : " as *u8); sx_num(N) 64 sx_puts(" mismatches (scalar==vec) : " as *u8); sx_num(mism) 65 sx_puts(" vector instructions run : " as *u8); sx_num(vinstr) 66 sx_puts(" scalar ops replaced : " as *u8); sx_num(scalar_ops) 67 sx_puts(" -> vector MACHINE CODE executes correct FMA; one vec op = " as *u8); sx_num(SV_W); sx_puts(" lanes.\n" as *u8) 68 69 if mism != 0 { sys_exit(1); return 1 } 70 if vinstr >= scalar_ops { sys_exit(2); return 2 } 71 sys_exit(0) 72 return 0 73}