| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build goexperiment.simd |
| |
| package simd_test |
| |
| import ( |
| "simd" |
| "testing" |
| ) |
| |
| type signed interface { |
| ~int | ~int8 | ~int16 | ~int32 | ~int64 |
| } |
| |
| type unsigned interface { |
| ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
| } |
| |
| type integer interface { |
| ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
| } |
| |
| type float interface { |
| ~float32 | ~float64 |
| } |
| |
| type number interface { |
| ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 |
| } |
| |
| func TestInt8s(t *testing.T) { |
| // 64 elements = 512 bits |
| in1 := []int8{ |
| 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12, 13, -14, 15, -16, |
| 17, -18, 19, -20, 21, -22, 23, -24, 25, -26, 27, -28, 29, -30, 31, -32, |
| 33, -34, 35, -36, 37, -38, 39, -40, 41, -42, 43, -44, 45, -46, 47, -48, |
| 49, -50, 51, -52, 53, -54, 55, -56, 57, -58, 59, -60, 61, -62, 63, -64, |
| } |
| in2 := make([]int8, 64) |
| for i := range in2 { |
| in2[i] = 2 |
| } |
| |
| x := simd.LoadInt8s(in1) |
| y := simd.LoadInt8s(in2) |
| |
| if x.Len() <= 0 { |
| t.Errorf("Int8s.Len() returned <= 0") |
| } |
| |
| sum := x.Add(y) |
| diff := x.Sub(y) |
| neg := x.Neg() |
| abs := x.Abs() |
| |
| buf := make([]int8, x.Len()) |
| sum.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] + in2[i] |
| if buf[i] != expected { |
| t.Errorf("Add at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| diff.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] - in2[i] |
| if buf[i] != expected { |
| t.Errorf("Sub at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| neg.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := -in1[i] |
| if buf[i] != expected { |
| t.Errorf("Neg at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| abs.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] |
| if expected < 0 { |
| expected = -expected |
| } |
| if buf[i] != expected { |
| t.Errorf("Abs at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestInt16s(t *testing.T) { |
| // 32 elements = 512 bits |
| in1 := make([]int16, 32) |
| in2 := make([]int16, 32) |
| for i := range in1 { |
| in1[i] = int16((i + 1) * 100) |
| if i%2 != 0 { |
| in1[i] = -in1[i] |
| } |
| in2[i] = 10 |
| } |
| |
| x := simd.LoadInt16s(in1) |
| y := simd.LoadInt16s(in2) |
| |
| sum := x.Add(y) |
| buf := make([]int16, x.Len()) |
| sum.Store(buf) |
| |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] + in2[i] |
| if buf[i] != expected { |
| t.Errorf("Int16s Add at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllLeft |
| rotLeft := x.RotateAllLeft(3) |
| rotLeft.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := uint16(in1[i]) |
| expected := int16((val << 3) | (val >> 13)) |
| if buf[i] != expected { |
| t.Errorf("Int16s RotateAllLeft at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllRight with large distance |
| rotRight := x.RotateAllRight(19) |
| rotRight.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := uint16(in1[i]) |
| expected := int16((val >> 3) | (val << 13)) |
| if buf[i] != expected { |
| t.Errorf("Int16s RotateAllRight(19) at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestInt32s(t *testing.T) { |
| // 16 elements = 512 bits |
| in1 := make([]int32, 16) |
| in2 := make([]int32, 16) |
| for i := range in1 { |
| in1[i] = int32((i + 1) * 1000) |
| if i%2 != 0 { |
| in1[i] = -in1[i] |
| } |
| in2[i] = 100 |
| } |
| |
| x := simd.LoadInt32s(in1) |
| y := simd.LoadInt32s(in2) |
| |
| sum := x.Add(y) |
| buf := make([]int32, x.Len()) |
| sum.Store(buf) |
| |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] + in2[i] |
| if buf[i] != expected { |
| t.Errorf("Int32s Add at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllLeft |
| rotLeft := x.RotateAllLeft(5) |
| rotLeft.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := uint32(in1[i]) |
| expected := int32((val << 5) | (val >> 27)) |
| if buf[i] != expected { |
| t.Errorf("Int32s RotateAllLeft at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllRight with large distance |
| rotRight := x.RotateAllRight(37) |
| rotRight.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := uint32(in1[i]) |
| expected := int32((val >> 5) | (val << 27)) |
| if buf[i] != expected { |
| t.Errorf("Int32s RotateAllRight(37) at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestInt64s(t *testing.T) { |
| // 8 elements = 512 bits |
| in1 := make([]int64, 8) |
| in2 := make([]int64, 8) |
| for i := range in1 { |
| in1[i] = int64((i + 1) * 10000) |
| if i%2 != 0 { |
| in1[i] = -in1[i] |
| } |
| in2[i] = 1000 |
| } |
| |
| x := simd.LoadInt64s(in1) |
| y := simd.LoadInt64s(in2) |
| |
| sum := x.Add(y) |
| buf := make([]int64, x.Len()) |
| sum.Store(buf) |
| |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] + in2[i] |
| if buf[i] != expected { |
| t.Errorf("Int64s Add at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllLeft |
| rotLeft := x.RotateAllLeft(7) |
| rotLeft.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := uint64(in1[i]) |
| expected := int64((val << 7) | (val >> 57)) |
| if buf[i] != expected { |
| t.Errorf("Int64s RotateAllLeft at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllRight with large distance |
| rotRight := x.RotateAllRight(71) |
| rotRight.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := uint64(in1[i]) |
| expected := int64((val >> 7) | (val << 57)) |
| if buf[i] != expected { |
| t.Errorf("Int64s RotateAllRight(71) at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestUint8s(t *testing.T) { |
| // 64 elements = 512 bits |
| in1 := make([]uint8, 64) |
| in2 := make([]uint8, 64) |
| for i := range in1 { |
| in1[i] = uint8(i + 1) |
| in2[i] = 10 |
| } |
| |
| x := simd.LoadUint8s(in1) |
| y := simd.LoadUint8s(in2) |
| |
| avg := x.Average(y) |
| buf := make([]uint8, x.Len()) |
| avg.Store(buf) |
| |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := uint8((int(in1[i]) + int(in2[i]) + 1) >> 1) |
| if buf[i] != expected { |
| t.Errorf("Uint8s Average at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestFloat32s(t *testing.T) { |
| // 16 elements = 512 bits |
| in1 := make([]float32, 16) |
| in2 := make([]float32, 16) |
| for i := range in1 { |
| val := float32(i) + 1.5 |
| if i%2 != 0 { |
| val = -val |
| } |
| in1[i] = val |
| in2[i] = 0.5 |
| } |
| |
| x := simd.LoadFloat32s(in1) |
| y := simd.LoadFloat32s(in2) |
| |
| sum := x.Add(y) |
| buf := make([]float32, x.Len()) |
| sum.Store(buf) |
| |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] + in2[i] |
| if buf[i] != expected { |
| t.Errorf("Float32s Add at %d: got %f, want %f", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestFloat64s(t *testing.T) { |
| // 8 elements = 512 bits |
| in1 := make([]float64, 8) |
| in2 := make([]float64, 8) |
| for i := range in1 { |
| val := float64(i)*10.0 + 10.25 |
| if i%2 != 0 { |
| val = -val |
| } |
| in1[i] = val |
| in2[i] = 1.0 |
| } |
| |
| x := simd.LoadFloat64s(in1) |
| y := simd.LoadFloat64s(in2) |
| |
| mul := x.Mul(y) |
| buf := make([]float64, x.Len()) |
| mul.Store(buf) |
| |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| expected := in1[i] * in2[i] |
| if buf[i] != expected { |
| t.Errorf("Float64s Mul at %d: got %f, want %f", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestUint16s(t *testing.T) { |
| in1 := make([]uint16, 32) |
| for i := range in1 { |
| in1[i] = uint16((i + 1) * 100) |
| } |
| |
| x := simd.LoadUint16s(in1) |
| buf := make([]uint16, x.Len()) |
| |
| // Test RotateAllLeft |
| rotLeft := x.RotateAllLeft(3) |
| rotLeft.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := in1[i] |
| expected := (val << 3) | (val >> 13) |
| if buf[i] != expected { |
| t.Errorf("Uint16s RotateAllLeft at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllRight with large distance |
| rotRight := x.RotateAllRight(19) |
| rotRight.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := in1[i] |
| expected := (val >> 3) | (val << 13) |
| if buf[i] != expected { |
| t.Errorf("Uint16s RotateAllRight(19) at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestUint32s(t *testing.T) { |
| in1 := make([]uint32, 16) |
| for i := range in1 { |
| in1[i] = uint32((i + 1) * 1000) |
| } |
| |
| x := simd.LoadUint32s(in1) |
| buf := make([]uint32, x.Len()) |
| |
| // Test RotateAllLeft |
| rotLeft := x.RotateAllLeft(5) |
| rotLeft.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := in1[i] |
| expected := (val << 5) | (val >> 27) |
| if buf[i] != expected { |
| t.Errorf("Uint32s RotateAllLeft at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllRight with large distance |
| rotRight := x.RotateAllRight(37) |
| rotRight.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := in1[i] |
| expected := (val >> 5) | (val << 27) |
| if buf[i] != expected { |
| t.Errorf("Uint32s RotateAllRight(37) at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| func TestUint64s(t *testing.T) { |
| in1 := make([]uint64, 8) |
| for i := range in1 { |
| in1[i] = uint64((i + 1) * 10000) |
| } |
| |
| x := simd.LoadUint64s(in1) |
| buf := make([]uint64, x.Len()) |
| |
| // Test RotateAllLeft |
| rotLeft := x.RotateAllLeft(7) |
| rotLeft.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := in1[i] |
| expected := (val << 7) | (val >> 57) |
| if buf[i] != expected { |
| t.Errorf("Uint64s RotateAllLeft at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| |
| // Test RotateAllRight with large distance |
| rotRight := x.RotateAllRight(71) |
| rotRight.Store(buf) |
| for i := 0; i < x.Len() && i < len(in1); i++ { |
| val := in1[i] |
| expected := (val >> 7) | (val << 57) |
| if buf[i] != expected { |
| t.Errorf("Uint64s RotateAllRight(71) at %d: got %d, want %d", i, buf[i], expected) |
| } |
| } |
| } |
| |
| type HasStoreLen[E number] interface { |
| Store(s []E) |
| Len() int |
| } |
| |
| func testBroadcast[E number, V HasStoreLen[E]](t *testing.T, x E, f func(e E) V) { |
| v := f(x) |
| s := make([]E, v.Len()) |
| v.Store(s) |
| for _, e := range s { |
| if e != x { |
| t.Errorf("Expected %v, saw %v", x, e) |
| } |
| } |
| } |
| |
| func TestBroadcast(t *testing.T) { |
| testBroadcast(t, int8(-2), simd.BroadcastInt8s) |
| testBroadcast(t, int16(-2), simd.BroadcastInt16s) |
| testBroadcast(t, int32(-2), simd.BroadcastInt32s) |
| testBroadcast(t, int64(-2), simd.BroadcastInt64s) |
| |
| testBroadcast(t, uint8(99), simd.BroadcastUint8s) |
| testBroadcast(t, uint16(9999), simd.BroadcastUint16s) |
| testBroadcast(t, uint32(99991111), simd.BroadcastUint32s) |
| testBroadcast(t, uint64(112233445599887766), simd.BroadcastUint64s) |
| |
| testBroadcast(t, float32(99991111), simd.BroadcastFloat32s) |
| testBroadcast(t, float64(112233445599887766), simd.BroadcastFloat64s) |
| } |