blob: 543249b1f83f84d8d4b79dc756c4ee9f78c0271e [file]
// 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) }},
})
}