// 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" ) // testSVEReduceSum checks a float ReduceSum. The values are small integers, // so every partial sum is exact and the result does not depend on the order // FADDV adds the lanes in. func testSVEReduceSum[T float32 | float64, V any](t *testing.T, name string, n int, load func([]T) V, sum func(V) T) { t.Helper() xs := make([]T, n) for start := -20; start <= 20; start += 7 { var want T for i := range xs { xs[i] = T(start + 3*i) want += xs[i] } if got := sum(load(xs)); got != want { t.Errorf("%s(%v) = %v, want %v", name, xs, got, want) } } inf := T(math.Inf(1)) for _, c := range []struct { lane int val T isNaN bool wantInf bool }{ {0, T(math.NaN()), true, false}, {n - 1, T(math.NaN()), true, false}, {n / 2, inf, false, true}, } { for i := range xs { xs[i] = 1 } xs[c.lane] = c.val got := sum(load(xs)) switch { case c.isNaN && got == got: t.Errorf("%s with NaN in lane %d = %v, want NaN", name, c.lane, got) case c.wantInf && got != inf: t.Errorf("%s with +Inf in lane %d = %v, want +Inf", name, c.lane, got) } } } func TestReduceSumSVE(t *testing.T) { if !archsimd.ARM64.SVE() { t.Skip("no SVE") } testSVEReduceSum(t, "Float32s.ReduceSum", archsimd.Float32s{}.Len(), archsimd.LoadFloat32s, archsimd.Float32s.ReduceSum) testSVEReduceSum(t, "Float64s.ReduceSum", archsimd.Float64s{}.Len(), archsimd.LoadFloat64s, archsimd.Float64s.ReduceSum) } // testSVEReduceMax checks a float ReduceMax with the maximum in each lane, // with NaN, and with signed zeros. func testSVEReduceMax[T float32 | float64, V any](t *testing.T, name string, n int, load func([]T) V, reduce func(V) T) { t.Helper() xs := make([]T, n) for lane := range xs { for i := range xs { xs[i] = T(-3*i - 1) } xs[lane] = 5 if got := reduce(load(xs)); got != 5 { t.Errorf("%s(%v) = %v, want 5", name, xs, got) } } for i := range xs { xs[i] = T(math.Inf(-1)) } if got := reduce(load(xs)); got != T(math.Inf(-1)) { t.Errorf("%s(all -Inf) = %v, want -Inf", name, got) } for _, lane := range []int{0, n / 2, n - 1} { for i := range xs { xs[i] = T(i) } xs[lane] = T(math.NaN()) if got := reduce(load(xs)); got == got { t.Errorf("%s with NaN in lane %d = %v, want NaN", name, lane, got) } } negZero := T(math.Copysign(0, -1)) for _, lane := range []int{0, n - 1} { for i := range xs { xs[i] = negZero } xs[lane] = 0 if got := reduce(load(xs)); got != 0 || math.Signbit(float64(got)) { t.Errorf("%s of signed zeros with +0 in lane %d = %v, want +0", name, lane, got) } } } func TestReduceMaxSVE(t *testing.T) { if !archsimd.ARM64.SVE() { t.Skip("no SVE") } testSVEReduceMax(t, "Float32s.ReduceMax", archsimd.Float32s{}.Len(), archsimd.LoadFloat32s, archsimd.Float32s.ReduceMax) testSVEReduceMax(t, "Float64s.ReduceMax", archsimd.Float64s{}.Len(), archsimd.LoadFloat64s, archsimd.Float64s.ReduceMax) }