// 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 && arm64 package simd_test import ( "math" "simd/archsimd" "testing" ) type sveShiftCase[V any] struct { shift uint64 f func(V) V // x.ShiftAllLeft(shift) with shift a constant } // testSVEShiftAllLeft checks ShiftAllLeft by every amount in amounts, passed // as a variable, and by the constant amounts in consts, against Go's <<. func testSVEShiftAllLeft[T int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64, V any]( t *testing.T, name string, n int, load func([]T) V, store func(V, []T), shift func(V, uint64) V, consts []sveShiftCase[V]) { t.Helper() xs := make([]T, n) for i := range xs { xs[i] = T(i*37 - 5) // mixes signs and high bits } got := make([]T, n) check := func(s uint64, how string) { t.Helper() for i, x := range xs { if want := x << s; got[i] != want { t.Errorf("%s.ShiftAllLeft(%d) %s: lane %d = %v, want %v", name, s, how, i, got[i], want) return } } } for _, s := range []uint64{0, 1, 3, 7, 8, 15, 16, 31, 32, 63, 64, 65, 255, 256, 1 << 40, math.MaxUint64} { store(shift(load(xs), s), got) check(s, "by variable") } for _, c := range consts { store(c.f(load(xs)), got) check(c.shift, "by constant") } } func TestShiftAllLeftSVE(t *testing.T) { if !archsimd.ARM64.SVE() { t.Skip("no SVE") } testSVEShiftAllLeft(t, "Int8s", archsimd.Int8s{}.Len(), archsimd.LoadInt8s, archsimd.Int8s.Store, archsimd.Int8s.ShiftAllLeft, []sveShiftCase[archsimd.Int8s]{ {3, func(x archsimd.Int8s) archsimd.Int8s { return x.ShiftAllLeft(3) }}, {7, func(x archsimd.Int8s) archsimd.Int8s { return x.ShiftAllLeft(7) }}, {8, func(x archsimd.Int8s) archsimd.Int8s { return x.ShiftAllLeft(8) }}, }) testSVEShiftAllLeft(t, "Uint8s", archsimd.Uint8s{}.Len(), archsimd.LoadUint8s, archsimd.Uint8s.Store, archsimd.Uint8s.ShiftAllLeft, []sveShiftCase[archsimd.Uint8s]{ {1, func(x archsimd.Uint8s) archsimd.Uint8s { return x.ShiftAllLeft(1) }}, {200, func(x archsimd.Uint8s) archsimd.Uint8s { return x.ShiftAllLeft(200) }}, }) testSVEShiftAllLeft(t, "Int16s", archsimd.Int16s{}.Len(), archsimd.LoadInt16s, archsimd.Int16s.Store, archsimd.Int16s.ShiftAllLeft, []sveShiftCase[archsimd.Int16s]{ {15, func(x archsimd.Int16s) archsimd.Int16s { return x.ShiftAllLeft(15) }}, {16, func(x archsimd.Int16s) archsimd.Int16s { return x.ShiftAllLeft(16) }}, }) testSVEShiftAllLeft(t, "Uint16s", archsimd.Uint16s{}.Len(), archsimd.LoadUint16s, archsimd.Uint16s.Store, archsimd.Uint16s.ShiftAllLeft, []sveShiftCase[archsimd.Uint16s]{ {4, func(x archsimd.Uint16s) archsimd.Uint16s { return x.ShiftAllLeft(4) }}, }) testSVEShiftAllLeft(t, "Int32s", archsimd.Int32s{}.Len(), archsimd.LoadInt32s, archsimd.Int32s.Store, archsimd.Int32s.ShiftAllLeft, []sveShiftCase[archsimd.Int32s]{ {23, func(x archsimd.Int32s) archsimd.Int32s { return x.ShiftAllLeft(23) }}, {31, func(x archsimd.Int32s) archsimd.Int32s { return x.ShiftAllLeft(31) }}, {32, func(x archsimd.Int32s) archsimd.Int32s { return x.ShiftAllLeft(32) }}, }) testSVEShiftAllLeft(t, "Uint32s", archsimd.Uint32s{}.Len(), archsimd.LoadUint32s, archsimd.Uint32s.Store, archsimd.Uint32s.ShiftAllLeft, []sveShiftCase[archsimd.Uint32s]{ {0, func(x archsimd.Uint32s) archsimd.Uint32s { return x.ShiftAllLeft(0) }}, }) testSVEShiftAllLeft(t, "Int64s", archsimd.Int64s{}.Len(), archsimd.LoadInt64s, archsimd.Int64s.Store, archsimd.Int64s.ShiftAllLeft, []sveShiftCase[archsimd.Int64s]{ {52, func(x archsimd.Int64s) archsimd.Int64s { return x.ShiftAllLeft(52) }}, {63, func(x archsimd.Int64s) archsimd.Int64s { return x.ShiftAllLeft(63) }}, {64, func(x archsimd.Int64s) archsimd.Int64s { return x.ShiftAllLeft(64) }}, }) testSVEShiftAllLeft(t, "Uint64s", archsimd.Uint64s{}.Len(), archsimd.LoadUint64s, archsimd.Uint64s.Store, archsimd.Uint64s.ShiftAllLeft, []sveShiftCase[archsimd.Uint64s]{ {33, func(x archsimd.Uint64s) archsimd.Uint64s { return x.ShiftAllLeft(33) }}, }) }