1
2
3
4
5
6
7
8
9
10
11
12
13
14 package simd_test
15
16 import (
17 "math"
18 "simd/archsimd"
19 "testing"
20 )
21
22
23
24 const sveMaxBytes = 32
25
26
27
28 func testSVEBinary[T number, V any](t *testing.T, pool []T, elemBytes, active int,
29 load func([]T) V, f func(V, V) V, store func(V, []T), want func([]T, []T) []T) {
30 t.Helper()
31 count := sveMaxBytes / elemBytes
32 forSlicePair(t, pool, count, func(x, y []T) bool {
33 t.Helper()
34 g := make([]T, count)
35 store(f(load(x), load(y)), g)
36 w := want(x, y)
37 return checkSlicesLogInput(t, g[:active], w[:active], 0.0, func() {
38 t.Helper()
39 t.Logf("x=%v", x)
40 t.Logf("y=%v", y)
41 })
42 })
43 }
44
45 func testInt8sBinary(t *testing.T, f func(_, _ archsimd.Int8s) archsimd.Int8s, want func(_, _ []int8) []int8) {
46 var z archsimd.Int8s
47 testSVEBinary(t, int8s, 1, z.Len(), archsimd.LoadInt8s, f, archsimd.Int8s.Store, want)
48 }
49
50 func testInt16sBinary(t *testing.T, f func(_, _ archsimd.Int16s) archsimd.Int16s, want func(_, _ []int16) []int16) {
51 var z archsimd.Int16s
52 testSVEBinary(t, int16s, 2, z.Len(), archsimd.LoadInt16s, f, archsimd.Int16s.Store, want)
53 }
54
55 func testInt32sBinary(t *testing.T, f func(_, _ archsimd.Int32s) archsimd.Int32s, want func(_, _ []int32) []int32) {
56 var z archsimd.Int32s
57 testSVEBinary(t, int32s, 4, z.Len(), archsimd.LoadInt32s, f, archsimd.Int32s.Store, want)
58 }
59
60 func testInt64sBinary(t *testing.T, f func(_, _ archsimd.Int64s) archsimd.Int64s, want func(_, _ []int64) []int64) {
61 var z archsimd.Int64s
62 testSVEBinary(t, int64s, 8, z.Len(), archsimd.LoadInt64s, f, archsimd.Int64s.Store, want)
63 }
64
65 func testUint8sBinary(t *testing.T, f func(_, _ archsimd.Uint8s) archsimd.Uint8s, want func(_, _ []uint8) []uint8) {
66 var z archsimd.Uint8s
67 testSVEBinary(t, uint8s, 1, z.Len(), archsimd.LoadUint8s, f, archsimd.Uint8s.Store, want)
68 }
69
70 func testFloat32sBinary(t *testing.T, f func(_, _ archsimd.Float32s) archsimd.Float32s, want func(_, _ []float32) []float32) {
71 var z archsimd.Float32s
72 testSVEBinary(t, float32s, 4, z.Len(), archsimd.LoadFloat32s, f, archsimd.Float32s.Store, want)
73 }
74
75 func testFloat64sBinary(t *testing.T, f func(_, _ archsimd.Float64s) archsimd.Float64s, want func(_, _ []float64) []float64) {
76 var z archsimd.Float64s
77 testSVEBinary(t, float64s, 8, z.Len(), archsimd.LoadFloat64s, f, archsimd.Float64s.Store, want)
78 }
79
80 func TestAddSVE(t *testing.T) {
81 if !archsimd.ARM64.SVE() {
82 t.Skip("no SVE")
83 }
84 testInt8sBinary(t, archsimd.Int8s.Add, addSlice[int8])
85 testInt16sBinary(t, archsimd.Int16s.Add, addSlice[int16])
86 testInt32sBinary(t, archsimd.Int32s.Add, addSlice[int32])
87 testInt64sBinary(t, archsimd.Int64s.Add, addSlice[int64])
88 testUint8sBinary(t, archsimd.Uint8s.Add, addSlice[uint8])
89 testFloat32sBinary(t, archsimd.Float32s.Add, addSlice[float32])
90 testFloat64sBinary(t, archsimd.Float64s.Add, addSlice[float64])
91 }
92
93 func TestSubSVE(t *testing.T) {
94 if !archsimd.ARM64.SVE() {
95 t.Skip("no SVE")
96 }
97 testInt8sBinary(t, archsimd.Int8s.Sub, subSlice[int8])
98 testInt16sBinary(t, archsimd.Int16s.Sub, subSlice[int16])
99 testInt32sBinary(t, archsimd.Int32s.Sub, subSlice[int32])
100 testInt64sBinary(t, archsimd.Int64s.Sub, subSlice[int64])
101 testUint8sBinary(t, archsimd.Uint8s.Sub, subSlice[uint8])
102 testFloat32sBinary(t, archsimd.Float32s.Sub, subSlice[float32])
103 testFloat64sBinary(t, archsimd.Float64s.Sub, subSlice[float64])
104 }
105
106
107
108 func testSVEUnary[T number, V any](t *testing.T, pool []T, elemBytes, active int,
109 load func([]T) V, f func(V) V, store func(V, []T), want func([]T) []T) {
110 t.Helper()
111 count := sveMaxBytes / elemBytes
112 forSlice(t, pool, count, func(x []T) bool {
113 t.Helper()
114 g := make([]T, count)
115 store(f(load(x)), g)
116 w := want(x)
117 return checkSlicesLogInput(t, g[:active], w[:active], 0.0, func() {
118 t.Helper()
119 t.Logf("x=%v", x)
120 })
121 })
122 }
123
124 func TestAbsSVE(t *testing.T) {
125 if !archsimd.ARM64.SVE() {
126 t.Skip("no SVE")
127 }
128 absSlice := func(x []int8) []int8 {
129 r := make([]int8, len(x))
130 for i, v := range x {
131 if v < 0 {
132 v = -v
133 }
134 r[i] = v
135 }
136 return r
137 }
138 var z archsimd.Int8s
139 testSVEUnary(t, int8s, 1, z.Len(), archsimd.LoadInt8s, archsimd.Int8s.Abs, archsimd.Int8s.Store, absSlice)
140 absFloat32 := func(x []float32) []float32 {
141 r := make([]float32, len(x))
142 for i, v := range x {
143 r[i] = float32(math.Abs(float64(v)))
144 }
145 return r
146 }
147 var zf archsimd.Float32s
148 testSVEUnary(t, float32s, 4, zf.Len(), archsimd.LoadFloat32s, archsimd.Float32s.Abs, archsimd.Float32s.Store, absFloat32)
149 }
150
151 func TestNegSVE(t *testing.T) {
152 if !archsimd.ARM64.SVE() {
153 t.Skip("no SVE")
154 }
155 negInt8 := func(x []int8) []int8 {
156 r := make([]int8, len(x))
157 for i, v := range x {
158 r[i] = -v
159 }
160 return r
161 }
162 negFloat64 := func(x []float64) []float64 {
163 r := make([]float64, len(x))
164 for i, v := range x {
165 r[i] = -v
166 }
167 return r
168 }
169 var zi archsimd.Int8s
170 testSVEUnary(t, int8s, 1, zi.Len(), archsimd.LoadInt8s, archsimd.Int8s.Neg, archsimd.Int8s.Store, negInt8)
171 var zf archsimd.Float64s
172 testSVEUnary(t, float64s, 8, zf.Len(), archsimd.LoadFloat64s, archsimd.Float64s.Neg, archsimd.Float64s.Store, negFloat64)
173 }
174
175 func TestSqrtSVE(t *testing.T) {
176 if !archsimd.ARM64.SVE() {
177 t.Skip("no SVE")
178 }
179 var in, got [4]float64
180 for i := range in {
181 in[i] = float64(i + 1)
182 }
183 v := archsimd.LoadFloat64s(in[:])
184 v.Sqrt().Store(got[:])
185 var z archsimd.Float64s
186 for i := 0; i < z.Len(); i++ {
187 if want := math.Sqrt(in[i]); got[i] != want {
188 t.Errorf("lane %d: Sqrt(%v) = %v, want %v", i, in[i], got[i], want)
189 }
190 }
191 }
192
193 func TestCeilSVE(t *testing.T) {
194 if !archsimd.ARM64.SVE() {
195 t.Skip("no SVE")
196 }
197 var in, got [4]float64
198 for i := range in {
199 in[i] = float64(i) - 1.5
200 }
201 v := archsimd.LoadFloat64s(in[:])
202 v.Ceil().Store(got[:])
203 var z archsimd.Float64s
204 for i := 0; i < z.Len(); i++ {
205 if want := math.Ceil(in[i]); got[i] != want {
206 t.Errorf("lane %d: Ceil(%v) = %v, want %v", i, in[i], got[i], want)
207 }
208 }
209 }
210
211 func TestFloorSVE(t *testing.T) {
212 if !archsimd.ARM64.SVE() {
213 t.Skip("no SVE")
214 }
215 var in, got [4]float64
216 for i := range in {
217 in[i] = float64(i) - 1.5
218 }
219 v := archsimd.LoadFloat64s(in[:])
220 v.Floor().Store(got[:])
221 var z archsimd.Float64s
222 for i := 0; i < z.Len(); i++ {
223 if want := math.Floor(in[i]); got[i] != want {
224 t.Errorf("lane %d: Floor(%v) = %v, want %v", i, in[i], got[i], want)
225 }
226 }
227 }
228
229 func TestTruncSVE(t *testing.T) {
230 if !archsimd.ARM64.SVE() {
231 t.Skip("no SVE")
232 }
233 var in, got [4]float64
234 for i := range in {
235 in[i] = float64(i) - 1.5
236 }
237 v := archsimd.LoadFloat64s(in[:])
238 v.Trunc().Store(got[:])
239 var z archsimd.Float64s
240 for i := 0; i < z.Len(); i++ {
241 if want := math.Trunc(in[i]); got[i] != want {
242 t.Errorf("lane %d: Trunc(%v) = %v, want %v", i, in[i], got[i], want)
243 }
244 }
245 }
246
247 func TestRoundSVE(t *testing.T) {
248 if !archsimd.ARM64.SVE() {
249 t.Skip("no SVE")
250 }
251 var in, got [4]float64
252 for i := range in {
253 in[i] = float64(i) - 1.5
254 }
255 v := archsimd.LoadFloat64s(in[:])
256 v.Round().Store(got[:])
257 var z archsimd.Float64s
258 for i := 0; i < z.Len(); i++ {
259 if want := math.RoundToEven(in[i]); got[i] != want {
260 t.Errorf("lane %d: Round(%v) = %v, want %v", i, in[i], got[i], want)
261 }
262 }
263 }
264
265 func TestAndSVE(t *testing.T) {
266 if !archsimd.ARM64.SVE() {
267 t.Skip("no SVE")
268 }
269 andInt8 := func(x, y []int8) []int8 {
270 r := make([]int8, len(x))
271 for i := range x {
272 r[i] = x[i] & y[i]
273 }
274 return r
275 }
276 testInt8sBinary(t, archsimd.Int8s.And, andInt8)
277 andUint64 := func(x, y []uint64) []uint64 {
278 r := make([]uint64, len(x))
279 for i := range x {
280 r[i] = x[i] & y[i]
281 }
282 return r
283 }
284 var z archsimd.Uint64s
285 testSVEBinary(t, uint64s, 8, z.Len(), archsimd.LoadUint64s, archsimd.Uint64s.And, archsimd.Uint64s.Store, andUint64)
286 }
287
288 func TestOrSVE(t *testing.T) {
289 if !archsimd.ARM64.SVE() {
290 t.Skip("no SVE")
291 }
292 orInt8 := func(x, y []int8) []int8 {
293 r := make([]int8, len(x))
294 for i := range x {
295 r[i] = x[i] | y[i]
296 }
297 return r
298 }
299 testInt8sBinary(t, archsimd.Int8s.Or, orInt8)
300 orUint64 := func(x, y []uint64) []uint64 {
301 r := make([]uint64, len(x))
302 for i := range x {
303 r[i] = x[i] | y[i]
304 }
305 return r
306 }
307 var z archsimd.Uint64s
308 testSVEBinary(t, uint64s, 8, z.Len(), archsimd.LoadUint64s, archsimd.Uint64s.Or, archsimd.Uint64s.Store, orUint64)
309 }
310
311 func TestXorSVE(t *testing.T) {
312 if !archsimd.ARM64.SVE() {
313 t.Skip("no SVE")
314 }
315 xorInt8 := func(x, y []int8) []int8 {
316 r := make([]int8, len(x))
317 for i := range x {
318 r[i] = x[i] ^ y[i]
319 }
320 return r
321 }
322 testInt8sBinary(t, archsimd.Int8s.Xor, xorInt8)
323 }
324
325 func TestAndNotSVE(t *testing.T) {
326 if !archsimd.ARM64.SVE() {
327 t.Skip("no SVE")
328 }
329 andNotInt8 := func(x, y []int8) []int8 {
330 r := make([]int8, len(x))
331 for i := range x {
332 r[i] = x[i] &^ y[i]
333 }
334 return r
335 }
336 testInt8sBinary(t, archsimd.Int8s.AndNot, andNotInt8)
337 }
338
View as plain text