1
2
3
4
5
6
7 package simd_test
8
9 import (
10 "simd/archsimd"
11 "testing"
12 )
13
14 func mustPanic(t *testing.T, name string, f func()) {
15 t.Helper()
16 defer func() {
17 if recover() == nil {
18 t.Errorf("%s: expected panic but did not panic", name)
19 }
20 }()
21 f()
22 }
23
24
25
26
27
28
29
30 func testLoadStorePart[T number, V any](t *testing.T, name string, load func([]T) (V, int), store func(V, []T) int, vlen int) {
31 t.Helper()
32
33 data := make([]T, vlen+8)
34 for i := range data {
35 data[i] = T(i + 1)
36 }
37
38
39
40
41 loadCases := []int{0, 1, vlen / 2, vlen - 1, vlen, vlen + 1, vlen + 8}
42 for ci, k := range loadCases {
43 if k < 0 || k > len(data) {
44 continue
45 }
46 src := data[:k]
47 if ci == 0 {
48 src = nil
49 }
50 v, gotN := load(src)
51 active := min(k, vlen)
52 if gotN != active {
53 t.Errorf("%s Load len=%d: returned n=%d, want %d", name, k, gotN, active)
54 }
55 out := make([]T, vlen)
56 store(v, out)
57 for i := 0; i < active; i++ {
58 if out[i] != data[i] {
59 t.Errorf("%s Load len=%d: lane %d = %v, want %v", name, k, i, out[i], data[i])
60 }
61 }
62 for i := active; i < vlen; i++ {
63 if out[i] != 0 {
64 t.Errorf("%s Load len=%d: lane %d = %v, want 0 (read past slice?)", name, k, i, out[i])
65 }
66 }
67 }
68
69
70
71 full, _ := load(data[:vlen])
72 const sentinel = 99
73 storeCases := []int{0, 1, vlen / 2, vlen - 1, vlen}
74 for ci, k := range storeCases {
75 if k < 0 {
76 continue
77 }
78 out := make([]T, vlen)
79 for i := range out {
80 out[i] = T(sentinel)
81 }
82 dst := out[:k]
83 if ci == 0 {
84 dst = nil
85 }
86 gotN := store(full, dst)
87 if gotN != k {
88 t.Errorf("%s Store len=%d: returned n=%d, want %d", name, k, gotN, k)
89 }
90 for i := 0; i < k; i++ {
91 if out[i] != data[i] {
92 t.Errorf("%s Store len=%d: elem %d = %v, want %v", name, k, i, out[i], data[i])
93 }
94 }
95 for i := k; i < vlen; i++ {
96 if out[i] != T(sentinel) {
97 t.Errorf("%s Store len=%d: elem %d = %v, want sentinel (wrote past len?)", name, k, i, out[i])
98 }
99 }
100 }
101 }
102
103 func TestLoadStorePartSVE(t *testing.T) {
104 if !archsimd.ARM64.SVE() {
105 t.Skip("no sve")
106 }
107 testLoadStorePart(t, "Int8s", archsimd.LoadInt8sPart, archsimd.Int8s.StorePart, archsimd.Int8s{}.Len())
108 testLoadStorePart(t, "Uint8s", archsimd.LoadUint8sPart, archsimd.Uint8s.StorePart, archsimd.Uint8s{}.Len())
109 testLoadStorePart(t, "Int16s", archsimd.LoadInt16sPart, archsimd.Int16s.StorePart, archsimd.Int16s{}.Len())
110 testLoadStorePart(t, "Uint16s", archsimd.LoadUint16sPart, archsimd.Uint16s.StorePart, archsimd.Uint16s{}.Len())
111 testLoadStorePart(t, "Int32s", archsimd.LoadInt32sPart, archsimd.Int32s.StorePart, archsimd.Int32s{}.Len())
112 testLoadStorePart(t, "Uint32s", archsimd.LoadUint32sPart, archsimd.Uint32s.StorePart, archsimd.Uint32s{}.Len())
113 testLoadStorePart(t, "Float32s", archsimd.LoadFloat32sPart, archsimd.Float32s.StorePart, archsimd.Float32s{}.Len())
114 testLoadStorePart(t, "Int64s", archsimd.LoadInt64sPart, archsimd.Int64s.StorePart, archsimd.Int64s{}.Len())
115 testLoadStorePart(t, "Uint64s", archsimd.LoadUint64sPart, archsimd.Uint64s.StorePart, archsimd.Uint64s{}.Len())
116 testLoadStorePart(t, "Float64s", archsimd.LoadFloat64sPart, archsimd.Float64s.StorePart, archsimd.Float64s{}.Len())
117 }
118
119
120
121 func TestLoadStorePlainSVE(t *testing.T) {
122 if !archsimd.ARM64.SVE() {
123 t.Skip("no sve")
124 }
125 var z archsimd.Int8s
126 n := z.Len()
127 data := make([]int8, n)
128 for i := range data {
129 data[i] = int8(i + 1)
130 }
131 v := archsimd.LoadInt8s(data)
132 out := make([]int8, n)
133 v.Store(out)
134 for i := range data {
135 if out[i] != data[i] {
136 t.Errorf("LoadInt8s/Store round-trip: lane %d = %d, want %d", i, out[i], data[i])
137 }
138 }
139 mustPanic(t, "LoadInt8s short", func() { archsimd.LoadInt8s(make([]int8, n-1)) })
140 mustPanic(t, "Int8s.Store short", func() { v.Store(make([]int8, n-1)) })
141 }
142
View as plain text