// 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) }