code wiki / (root) / nx_i8dot32_kat.nx

nx_i8dot32_kat.nx source

↩ module page · 56 lines · 1949 B

1// nx_i8dot32_kat.nx -- KAT for the new __f32_i8dot32 SSE intrinsic. 2// __f32_i8dot32(a:*i8[32], b:*f32[32]) = sum_{j<32} sext(a[j]) * b[j]. 3// Compared to a scalar hardware-op reference; exact-int regime so the 4// 4-lane-parallel accumulation is bit-identical to sequential. 5// expect_exit: 0 (77=mismatch) 6import "nx_syscalls.nx" 7import "nx_f32.nx" 8import "nx_f32_cvt.nx" 9 10func k_st4(p: *u8, idx: i64, bits: i64) -> i64 { 11 p[idx*4+0] = bits as u8 12 p[idx*4+1] = (bits>>8) as u8 13 p[idx*4+2] = (bits>>16) as u8 14 p[idx*4+3] = (bits>>24) as u8 15 return 0 16} 17 18func main() -> i64 { 19 let a: *u8 = sys_mmap(32) // 32 int8 20 let b: *u8 = sys_mmap(32 * 4) // 32 f32 packed 21 var j: i64 = 0 22 while j < 32 { 23 a[j] = (j - 16) as u8 // int8 -16..15 24 k_st4(b, j, nx_i32_to_f32((j % 3) + 1)) // f32 1,2,3,... 25 j = j + 1 26 } 27 // scalar reference (hardware ops, same as the intrinsic's mul/add). 28 var ref: i64 = 0 29 var k: i64 = 0 30 while k < 32 { 31 ref = __f32_add(ref, __f32_mul(nx_i32_to_f32(k - 16), nx_i32_to_f32((k % 3) + 1))) 32 k = k + 1 33 } 34 let got: i64 = __f32_i8dot32(a, b) 35 if got != ref { return 77 } 36 37 // second case: all a = +1 -> dot = sum(b) = per 3-cycle (1+2+3)*10 + 1+2 = 60+3 = 63.0 38 var j2: i64 = 0 39 while j2 < 32 { a[j2] = 1 as u8; j2 = j2 + 1 } 40 var ref2: i64 = 0 41 var k2: i64 = 0 42 while k2 < 32 { ref2 = __f32_add(ref2, nx_i32_to_f32((k2 % 3) + 1)); k2 = k2 + 1 } 43 let got2: i64 = __f32_i8dot32(a, b) 44 if got2 != ref2 { return 78 } 45 46 // third: negatives -- all a = -2 47 var j3: i64 = 0 48 while j3 < 32 { a[j3] = (0 - 2) as u8; j3 = j3 + 1 } 49 var ref3: i64 = 0 50 var k3: i64 = 0 51 while k3 < 32 { ref3 = __f32_add(ref3, __f32_mul(nx_i32_to_f32(0 - 2), nx_i32_to_f32((k3 % 3) + 1))); k3 = k3 + 1 } 52 let got3: i64 = __f32_i8dot32(a, b) 53 if got3 != ref3 { return 79 } 54 55 return 0 56}