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}