blob: 05d3e16126e0c4f3bc5db86539f2acc6e9a68e1a [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 && amd64
package simd_test
import (
"simd/archsimd"
"testing"
)
func TestFloatMinMax32AMD64(t *testing.T) {
for _, tc := range []struct {
name string
lanes int
run func([]float32, []float32, [4][]float32, bool, bool)
}{
{"Float32x8", 8, floatMinMax32x8},
{"Float32x16", 16, floatMinMax32x16},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.lanes == 16 && !archsimd.X86.AVX512() {
t.Skip("requires AVX512")
}
testFloatMinMax32(t, tc.lanes, tc.run)
})
}
}
func TestFloatMinMax64AMD64(t *testing.T) {
for _, tc := range []struct {
name string
lanes int
run func([]float64, []float64, [4][]float64, bool, bool)
}{
{"Float64x4", 4, floatMinMax64x4},
{"Float64x8", 8, floatMinMax64x8},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.lanes == 8 && !archsimd.X86.AVX512() {
t.Skip("requires AVX512")
}
testFloatMinMax64(t, tc.lanes, tc.run)
})
}
}
func floatMinMaxPlatformConfig() floatMinMaxConfig {
return floatMinMaxConfig{allowMasked: archsimd.X86.AVX512()}
}
func floatMinMaxMask32x4() archsimd.Mask32x4 {
return archsimd.Mask32x4FromBits(0x5)
}
func floatMinMaxMask64x2() archsimd.Mask64x2 {
return archsimd.Mask64x2FromBits(0x1)
}
//go:noinline
func floatMinMax32x8(a, b []float32, out [4][]float32, reverse, masked bool) {
x, y := archsimd.LoadFloat32x8(a), archsimd.LoadFloat32x8(b)
var minXY, minYX, maxXY, maxYX archsimd.Float32x8
if masked {
mask := archsimd.Mask32x8FromBits(0x55)
if reverse {
minYX, minXY = y.Min(x).Masked(mask), x.Min(y).Masked(mask)
maxYX, maxXY = y.Max(x).Masked(mask), x.Max(y).Masked(mask)
} else {
minXY, minYX = x.Min(y).Masked(mask), y.Min(x).Masked(mask)
maxXY, maxYX = x.Max(y).Masked(mask), y.Max(x).Masked(mask)
}
} else if reverse {
minYX, minXY = y.Min(x), x.Min(y)
maxYX, maxXY = y.Max(x), x.Max(y)
} else {
minXY, minYX = x.Min(y), y.Min(x)
maxXY, maxYX = x.Max(y), y.Max(x)
}
minXY.Store(out[0])
minYX.Store(out[1])
maxXY.Store(out[2])
maxYX.Store(out[3])
}
//go:noinline
func floatMinMax32x16(a, b []float32, out [4][]float32, reverse, masked bool) {
x, y := archsimd.LoadFloat32x16(a), archsimd.LoadFloat32x16(b)
var minXY, minYX, maxXY, maxYX archsimd.Float32x16
if masked {
mask := archsimd.Mask32x16FromBits(0x5555)
if reverse {
minYX, minXY = y.Min(x).Masked(mask), x.Min(y).Masked(mask)
maxYX, maxXY = y.Max(x).Masked(mask), x.Max(y).Masked(mask)
} else {
minXY, minYX = x.Min(y).Masked(mask), y.Min(x).Masked(mask)
maxXY, maxYX = x.Max(y).Masked(mask), y.Max(x).Masked(mask)
}
} else if reverse {
minYX, minXY = y.Min(x), x.Min(y)
maxYX, maxXY = y.Max(x), x.Max(y)
} else {
minXY, minYX = x.Min(y), y.Min(x)
maxXY, maxYX = x.Max(y), y.Max(x)
}
minXY.Store(out[0])
minYX.Store(out[1])
maxXY.Store(out[2])
maxYX.Store(out[3])
}
//go:noinline
func floatMinMax64x4(a, b []float64, out [4][]float64, reverse, masked bool) {
x, y := archsimd.LoadFloat64x4(a), archsimd.LoadFloat64x4(b)
var minXY, minYX, maxXY, maxYX archsimd.Float64x4
if masked {
mask := archsimd.Mask64x4FromBits(0x5)
if reverse {
minYX, minXY = y.Min(x).Masked(mask), x.Min(y).Masked(mask)
maxYX, maxXY = y.Max(x).Masked(mask), x.Max(y).Masked(mask)
} else {
minXY, minYX = x.Min(y).Masked(mask), y.Min(x).Masked(mask)
maxXY, maxYX = x.Max(y).Masked(mask), y.Max(x).Masked(mask)
}
} else if reverse {
minYX, minXY = y.Min(x), x.Min(y)
maxYX, maxXY = y.Max(x), x.Max(y)
} else {
minXY, minYX = x.Min(y), y.Min(x)
maxXY, maxYX = x.Max(y), y.Max(x)
}
minXY.Store(out[0])
minYX.Store(out[1])
maxXY.Store(out[2])
maxYX.Store(out[3])
}
//go:noinline
func floatMinMax64x8(a, b []float64, out [4][]float64, reverse, masked bool) {
x, y := archsimd.LoadFloat64x8(a), archsimd.LoadFloat64x8(b)
var minXY, minYX, maxXY, maxYX archsimd.Float64x8
if masked {
mask := archsimd.Mask64x8FromBits(0x55)
if reverse {
minYX, minXY = y.Min(x).Masked(mask), x.Min(y).Masked(mask)
maxYX, maxXY = y.Max(x).Masked(mask), x.Max(y).Masked(mask)
} else {
minXY, minYX = x.Min(y).Masked(mask), y.Min(x).Masked(mask)
maxXY, maxYX = x.Max(y).Masked(mask), y.Max(x).Masked(mask)
}
} else if reverse {
minYX, minXY = y.Min(x), x.Min(y)
maxYX, maxXY = y.Max(x), x.Max(y)
} else {
minXY, minYX = x.Min(y), y.Min(x)
maxXY, maxYX = x.Max(y), y.Max(x)
}
minXY.Store(out[0])
minYX.Store(out[1])
maxXY.Store(out[2])
maxYX.Store(out[3])
}