aboutsummaryrefslogtreecommitdiff
path: root/src/simd
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2025-08-19 15:26:19 -0400
committerDavid Chase <drchase@google.com>2025-08-20 15:10:27 -0700
commitaf6475df7338155cf6bfca2caf3686b7f8b2f2e2 (patch)
tree5e687352baf0e6b8719d430648257182266901db /src/simd
parentede64cf0d82e49edbdcb5107a80bbdac3217b55b (diff)
downloadgo-af6475df7338155cf6bfca2caf3686b7f8b2f2e2.tar.xz
[dev.simd] simd: add testing hooks for size-changing conversions
and adds some tests of size-changing conversions. IMO the template naming conventions in genfiles are getting grubby, and I plan to change them in an immediately following CL. Change-Id: I4a72e8a8c9e9806fab60570dff4c87a754e427c5 Reviewed-on: https://go-review.googlesource.com/c/go/+/697456 Commit-Queue: David Chase <drchase@google.com> Reviewed-by: Junyang Shao <shaojunyang@google.com> TryBot-Bypass: David Chase <drchase@google.com>
Diffstat (limited to 'src/simd')
-rw-r--r--src/simd/genfiles.go98
-rw-r--r--src/simd/simulation_helpers_test.go46
-rw-r--r--src/simd/unary_helpers_test.go855
-rw-r--r--src/simd/unary_test.go28
4 files changed, 962 insertions, 65 deletions
diff --git a/src/simd/genfiles.go b/src/simd/genfiles.go
index be149ef637..3d9b26a6b0 100644
--- a/src/simd/genfiles.go
+++ b/src/simd/genfiles.go
@@ -21,12 +21,15 @@ import (
"text/template"
)
+type resultTypeFunc func(t string, w, c int) (ot string, ow int, oc int)
+
// shapes describes a combination of vector widths and various element types
type shapes struct {
vecs []int // Vector bit width for this shape.
ints []int // Int element bit width(s) for this shape
uints []int // Unsigned int element bit width(s) for this shape
floats []int // Float element bit width(s) for this shape
+ output resultTypeFunc
}
// shapeAndTemplate is a template and the set of shapes on which it will be expanded
@@ -35,6 +38,26 @@ type shapeAndTemplate struct {
t *template.Template
}
+func (sat shapeAndTemplate) target(outType string, width int) shapeAndTemplate {
+ newSat := sat
+ newShape := *sat.s
+ newShape.output = func(t string, w, c int) (ot string, ow int, oc int) {
+ return outType, width, c
+ }
+ newSat.s = &newShape
+ return newSat
+}
+
+func (sat shapeAndTemplate) shrinkTo(outType string, by int) shapeAndTemplate {
+ newSat := sat
+ newShape := *sat.s
+ newShape.output = func(t string, w, c int) (ot string, ow int, oc int) {
+ return outType, w / by, c * by
+ }
+ newSat.s = &newShape
+ return newSat
+}
+
var allShapes = &shapes{
vecs: []int{128, 256, 512},
ints: []int{8, 16, 32, 64},
@@ -42,14 +65,6 @@ var allShapes = &shapes{
floats: []int{32, 64},
}
-// these are the shapes that are currently converted to int32
-// (not all conversions are available, yet)
-var convert32Shapes = &shapes{
-
- vecs: []int{128, 256, 512},
- floats: []int{32},
-}
-
var avx512Shapes = &shapes{
vecs: []int{512},
ints: []int{8, 16, 32, 64},
@@ -108,22 +123,44 @@ type templateData struct {
Base string // the capitalized Base Type of the vector, e.g., "Float"
Type string // the element type, e.g. "float32"
OxFF string // a mask for the lowest 'count' bits
+
+ Ovec string
+ Otype string
+ OType string
+ Ocount int
}
func (t templateData) As128BitVec() string {
return fmt.Sprintf("%s%dx%d", t.Base, t.Width, 128/t.Width)
}
-func oneTemplate(t *template.Template, baseType string, width, count int, out io.Writer) {
+func oneTemplate(t *template.Template, baseType string, width, count int, out io.Writer, rtf resultTypeFunc) {
b := width * count
if b < 128 || b > 512 {
return
}
+
+ ot, ow, oc := baseType, width, count
+ if rtf != nil {
+ ot, ow, oc = rtf(ot, ow, oc)
+ if ow*oc > 512 || ow*oc < 128 || ow < 8 || ow > 64 {
+ return
+ }
+ // TODO someday we will support conversions to 16-bit floats
+ if ot == "float" && ow < 32 {
+ return
+ }
+ }
+ ovType := fmt.Sprintf("%s%dx%d", strings.ToUpper(ot[:1])+ot[1:], ow, oc)
+ oeType := fmt.Sprintf("%s%d", ot, ow)
+ oEType := fmt.Sprintf("%s%d", strings.ToUpper(ot[:1])+ot[1:], ow)
+
+ wxc := fmt.Sprintf("%dx%d", width, count)
BaseType := strings.ToUpper(baseType[:1]) + baseType[1:]
+ vType := fmt.Sprintf("%s%s", BaseType, wxc)
eType := fmt.Sprintf("%s%d", baseType, width)
- wxc := fmt.Sprintf("%dx%d", width, count)
+
bxc := fmt.Sprintf("%dx%d", 8, count*(width/8))
- vType := fmt.Sprintf("%s%s", BaseType, wxc)
aOrAn := "a"
if strings.Contains("aeiou", baseType[:1]) {
aOrAn = "an"
@@ -140,6 +177,10 @@ func oneTemplate(t *template.Template, baseType string, width, count int, out io
Base: BaseType,
Type: eType,
OxFF: oxFF,
+ Ovec: ovType,
+ Otype: oeType,
+ Ocount: oc,
+ OType: oEType,
})
}
@@ -154,15 +195,15 @@ func (sat shapeAndTemplate) forTemplates(out io.Writer) {
for _, v := range vecs {
for _, w := range ints {
c := v / w
- oneTemplate(t, "int", w, c, out)
+ oneTemplate(t, "int", w, c, out, sat.s.output)
}
for _, w := range uints {
c := v / w
- oneTemplate(t, "uint", w, c, out)
+ oneTemplate(t, "uint", w, c, out, sat.s.output)
}
for _, w := range floats {
c := v / w
- oneTemplate(t, "float", w, c, out)
+ oneTemplate(t, "float", w, c, out, sat.s.output)
}
}
}
@@ -271,15 +312,16 @@ func test{{.Vec}}UnaryFlaky(t *testing.T, f func(x simd.{{.Vec}}) simd.{{.Vec}},
}
`)
-var unaryTemplateToInt32 = shapedTemplateOf(convert32Shapes, "unary_int32_helpers", `
-// test{{.Vec}}Unary tests the simd unary method f against the expected behavior generated by want
-func test{{.Vec}}UnaryToInt32(t *testing.T, f func(x simd.{{.Vec}}) simd.Int32x{{.Count}}, want func(x []{{.Type}}) []int32) {
+var convertTemplate = templateOf("convert_helpers", `
+// test{{.Vec}}ConvertTo{{.OType}} tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func test{{.Vec}}ConvertTo{{.OType}}(t *testing.T, f func(x simd.{{.Vec}}) simd.{{.Ovec}}, want func(x []{{.Type}}) []{{.Otype}}) {
n := {{.Count}}
t.Helper()
forSlice(t, {{.Type}}s, n, func(x []{{.Type}}) bool {
t.Helper()
a := simd.Load{{.Vec}}Slice(x)
- g := make([]int32, n)
+ g := make([]{{.Otype}}, n)
f(a).StoreSlice(g)
w := want(x)
return checkSlicesLogInput(t, g, w, 0.0, func() {t.Helper(); t.Logf("x=%v", x)})
@@ -287,21 +329,9 @@ func test{{.Vec}}UnaryToInt32(t *testing.T, f func(x simd.{{.Vec}}) simd.Int32x{
}
`)
-var unaryTemplateToUint32 = shapedTemplateOf(convert32Shapes, "unary_uint32_helpers", `
-// test{{.Vec}}Unary tests the simd unary method f against the expected behavior generated by want
-func test{{.Vec}}UnaryToUint32(t *testing.T, f func(x simd.{{.Vec}}) simd.Uint32x{{.Count}}, want func(x []{{.Type}}) []uint32) {
- n := {{.Count}}
- t.Helper()
- forSlice(t, {{.Type}}s, n, func(x []{{.Type}}) bool {
- t.Helper()
- a := simd.Load{{.Vec}}Slice(x)
- g := make([]uint32, n)
- f(a).StoreSlice(g)
- w := want(x)
- return checkSlicesLogInput(t, g, w, 0.0, func() {t.Helper(); t.Logf("x=%v", x)})
- })
-}
-`)
+var unaryToInt32 = convertTemplate.target("int", 32)
+var unaryToUint32 = convertTemplate.target("uint", 32)
+var unaryToUint16 = convertTemplate.target("uint", 16)
var binaryTemplate = templateOf("binary_helpers", `
// test{{.Vec}}Binary tests the simd binary method f against the expected behavior generated by want
@@ -755,7 +785,7 @@ func main() {
one(*ush, unsafePrologue, unsafePATemplate)
}
if *uh != "" {
- one(*uh, curryTestPrologue("unary simd methods"), unaryTemplate, unaryTemplateToInt32, unaryTemplateToUint32, unaryFlakyTemplate)
+ one(*uh, curryTestPrologue("unary simd methods"), unaryTemplate, unaryToInt32, unaryToUint32, unaryToUint16, unaryFlakyTemplate)
}
if *bh != "" {
one(*bh, curryTestPrologue("binary simd methods"), binaryTemplate)
diff --git a/src/simd/simulation_helpers_test.go b/src/simd/simulation_helpers_test.go
index 8677216d9f..2f040ffb3e 100644
--- a/src/simd/simulation_helpers_test.go
+++ b/src/simd/simulation_helpers_test.go
@@ -32,7 +32,7 @@ func notEqual[T number](x, y T) bool {
func abs[T number](x T) T {
// TODO this will need a non-standard FP-equality test.
if x == 0 { // true if x is -0.
- return x // this is not a negative zero
+ return 0 // this is not a negative zero
}
if x < 0 {
return -x
@@ -108,8 +108,16 @@ func fma[T float](x, y, z T) T {
return T(math.FMA(float64(x), float64(y), float64(z)))
}
-func toInt32[T number](x T) int32 {
- return int32(x)
+func toUint8[T number](x T) uint8 {
+ return uint8(x)
+}
+
+func toUint16[T number](x T) uint16 {
+ return uint16(x)
+}
+
+func toUint64[T number](x T) uint64 {
+ return uint64(x)
}
func toUint32[T number](x T) uint32 {
@@ -126,6 +134,30 @@ func toUint32[T number](x T) uint32 {
return uint32(x)
}
+func toInt8[T number](x T) int8 {
+ return int8(x)
+}
+
+func toInt16[T number](x T) int16 {
+ return int16(x)
+}
+
+func toInt32[T number](x T) int32 {
+ return int32(x)
+}
+
+func toInt64[T number](x T) int64 {
+ return int64(x)
+}
+
+func toFloat32[T number](x T) float32 {
+ return float32(x)
+}
+
+func toFloat64[T number](x T) float64 {
+ return float64(x)
+}
+
func ceilResidueForPrecision[T float](i int) func(T) T {
f := 1.0
for i > 0 {
@@ -240,11 +272,3 @@ func imaSlice[T integer](x, y, z []T) []T {
func fmaSlice[T float](x, y, z []T) []T {
return map3[T](fma)(x, y, z)
}
-
-func toInt32Slice[T number](x []T) []int32 {
- return map1[T](toInt32)(x)
-}
-
-func toUint32Slice[T number](x []T) []uint32 {
- return map1[T](toUint32)(x)
-}
diff --git a/src/simd/unary_helpers_test.go b/src/simd/unary_helpers_test.go
index f5b9e3b676..d99fd3c505 100644
--- a/src/simd/unary_helpers_test.go
+++ b/src/simd/unary_helpers_test.go
@@ -433,8 +433,99 @@ func testFloat64x8Unary(t *testing.T, f func(_ simd.Float64x8) simd.Float64x8, w
})
}
-// testFloat32x4Unary tests the simd unary method f against the expected behavior generated by want
-func testFloat32x4UnaryToInt32(t *testing.T, f func(x simd.Float32x4) simd.Int32x4, want func(x []float32) []int32) {
+// testInt8x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt8x16ConvertToInt32(t *testing.T, f func(x simd.Int8x16) simd.Int32x16, want func(x []int8) []int32) {
+ n := 16
+ t.Helper()
+ forSlice(t, int8s, n, func(x []int8) bool {
+ t.Helper()
+ a := simd.LoadInt8x16Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt16x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x8ConvertToInt32(t *testing.T, f func(x simd.Int16x8) simd.Int32x8, want func(x []int16) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x4ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x4ConvertToInt32(t *testing.T, f func(x simd.Int32x4) simd.Int32x4, want func(x []int32) []int32) {
+ n := 4
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x4Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint8x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint8x16ConvertToInt32(t *testing.T, f func(x simd.Uint8x16) simd.Int32x16, want func(x []uint8) []int32) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint8s, n, func(x []uint8) bool {
+ t.Helper()
+ a := simd.LoadUint8x16Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x8ConvertToInt32(t *testing.T, f func(x simd.Uint16x8) simd.Int32x8, want func(x []uint16) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x4ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x4ConvertToInt32(t *testing.T, f func(x simd.Uint32x4) simd.Int32x4, want func(x []uint32) []int32) {
+ n := 4
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x4Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x4ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x4ConvertToInt32(t *testing.T, f func(x simd.Float32x4) simd.Int32x4, want func(x []float32) []int32) {
n := 4
t.Helper()
forSlice(t, float32s, n, func(x []float32) bool {
@@ -447,8 +538,99 @@ func testFloat32x4UnaryToInt32(t *testing.T, f func(x simd.Float32x4) simd.Int32
})
}
-// testFloat32x8Unary tests the simd unary method f against the expected behavior generated by want
-func testFloat32x8UnaryToInt32(t *testing.T, f func(x simd.Float32x8) simd.Int32x8, want func(x []float32) []int32) {
+// testInt16x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x16ConvertToInt32(t *testing.T, f func(x simd.Int16x16) simd.Int32x16, want func(x []int16) []int32) {
+ n := 16
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x16Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x8ConvertToInt32(t *testing.T, f func(x simd.Int32x8) simd.Int32x8, want func(x []int32) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt64x4ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt64x4ConvertToInt32(t *testing.T, f func(x simd.Int64x4) simd.Int32x4, want func(x []int64) []int32) {
+ n := 4
+ t.Helper()
+ forSlice(t, int64s, n, func(x []int64) bool {
+ t.Helper()
+ a := simd.LoadInt64x4Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x16ConvertToInt32(t *testing.T, f func(x simd.Uint16x16) simd.Int32x16, want func(x []uint16) []int32) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x16Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x8ConvertToInt32(t *testing.T, f func(x simd.Uint32x8) simd.Int32x8, want func(x []uint32) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint64x4ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint64x4ConvertToInt32(t *testing.T, f func(x simd.Uint64x4) simd.Int32x4, want func(x []uint64) []int32) {
+ n := 4
+ t.Helper()
+ forSlice(t, uint64s, n, func(x []uint64) bool {
+ t.Helper()
+ a := simd.LoadUint64x4Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x8ConvertToInt32(t *testing.T, f func(x simd.Float32x8) simd.Int32x8, want func(x []float32) []int32) {
n := 8
t.Helper()
forSlice(t, float32s, n, func(x []float32) bool {
@@ -461,8 +643,84 @@ func testFloat32x8UnaryToInt32(t *testing.T, f func(x simd.Float32x8) simd.Int32
})
}
-// testFloat32x16Unary tests the simd unary method f against the expected behavior generated by want
-func testFloat32x16UnaryToInt32(t *testing.T, f func(x simd.Float32x16) simd.Int32x16, want func(x []float32) []int32) {
+// testFloat64x4ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat64x4ConvertToInt32(t *testing.T, f func(x simd.Float64x4) simd.Int32x4, want func(x []float64) []int32) {
+ n := 4
+ t.Helper()
+ forSlice(t, float64s, n, func(x []float64) bool {
+ t.Helper()
+ a := simd.LoadFloat64x4Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x16ConvertToInt32(t *testing.T, f func(x simd.Int32x16) simd.Int32x16, want func(x []int32) []int32) {
+ n := 16
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x16Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt64x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt64x8ConvertToInt32(t *testing.T, f func(x simd.Int64x8) simd.Int32x8, want func(x []int64) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, int64s, n, func(x []int64) bool {
+ t.Helper()
+ a := simd.LoadInt64x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x16ConvertToInt32(t *testing.T, f func(x simd.Uint32x16) simd.Int32x16, want func(x []uint32) []int32) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x16Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint64x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint64x8ConvertToInt32(t *testing.T, f func(x simd.Uint64x8) simd.Int32x8, want func(x []uint64) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint64s, n, func(x []uint64) bool {
+ t.Helper()
+ a := simd.LoadUint64x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x16ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x16ConvertToInt32(t *testing.T, f func(x simd.Float32x16) simd.Int32x16, want func(x []float32) []int32) {
n := 16
t.Helper()
forSlice(t, float32s, n, func(x []float32) bool {
@@ -475,8 +733,114 @@ func testFloat32x16UnaryToInt32(t *testing.T, f func(x simd.Float32x16) simd.Int
})
}
-// testFloat32x4Unary tests the simd unary method f against the expected behavior generated by want
-func testFloat32x4UnaryToUint32(t *testing.T, f func(x simd.Float32x4) simd.Uint32x4, want func(x []float32) []uint32) {
+// testFloat64x8ConvertToInt32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat64x8ConvertToInt32(t *testing.T, f func(x simd.Float64x8) simd.Int32x8, want func(x []float64) []int32) {
+ n := 8
+ t.Helper()
+ forSlice(t, float64s, n, func(x []float64) bool {
+ t.Helper()
+ a := simd.LoadFloat64x8Slice(x)
+ g := make([]int32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt8x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt8x16ConvertToUint32(t *testing.T, f func(x simd.Int8x16) simd.Uint32x16, want func(x []int8) []uint32) {
+ n := 16
+ t.Helper()
+ forSlice(t, int8s, n, func(x []int8) bool {
+ t.Helper()
+ a := simd.LoadInt8x16Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt16x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x8ConvertToUint32(t *testing.T, f func(x simd.Int16x8) simd.Uint32x8, want func(x []int16) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x4ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x4ConvertToUint32(t *testing.T, f func(x simd.Int32x4) simd.Uint32x4, want func(x []int32) []uint32) {
+ n := 4
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x4Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint8x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint8x16ConvertToUint32(t *testing.T, f func(x simd.Uint8x16) simd.Uint32x16, want func(x []uint8) []uint32) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint8s, n, func(x []uint8) bool {
+ t.Helper()
+ a := simd.LoadUint8x16Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x8ConvertToUint32(t *testing.T, f func(x simd.Uint16x8) simd.Uint32x8, want func(x []uint16) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x4ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x4ConvertToUint32(t *testing.T, f func(x simd.Uint32x4) simd.Uint32x4, want func(x []uint32) []uint32) {
+ n := 4
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x4Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x4ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x4ConvertToUint32(t *testing.T, f func(x simd.Float32x4) simd.Uint32x4, want func(x []float32) []uint32) {
n := 4
t.Helper()
forSlice(t, float32s, n, func(x []float32) bool {
@@ -489,8 +853,99 @@ func testFloat32x4UnaryToUint32(t *testing.T, f func(x simd.Float32x4) simd.Uint
})
}
-// testFloat32x8Unary tests the simd unary method f against the expected behavior generated by want
-func testFloat32x8UnaryToUint32(t *testing.T, f func(x simd.Float32x8) simd.Uint32x8, want func(x []float32) []uint32) {
+// testInt16x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x16ConvertToUint32(t *testing.T, f func(x simd.Int16x16) simd.Uint32x16, want func(x []int16) []uint32) {
+ n := 16
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x16Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x8ConvertToUint32(t *testing.T, f func(x simd.Int32x8) simd.Uint32x8, want func(x []int32) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt64x4ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt64x4ConvertToUint32(t *testing.T, f func(x simd.Int64x4) simd.Uint32x4, want func(x []int64) []uint32) {
+ n := 4
+ t.Helper()
+ forSlice(t, int64s, n, func(x []int64) bool {
+ t.Helper()
+ a := simd.LoadInt64x4Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x16ConvertToUint32(t *testing.T, f func(x simd.Uint16x16) simd.Uint32x16, want func(x []uint16) []uint32) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x16Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x8ConvertToUint32(t *testing.T, f func(x simd.Uint32x8) simd.Uint32x8, want func(x []uint32) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint64x4ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint64x4ConvertToUint32(t *testing.T, f func(x simd.Uint64x4) simd.Uint32x4, want func(x []uint64) []uint32) {
+ n := 4
+ t.Helper()
+ forSlice(t, uint64s, n, func(x []uint64) bool {
+ t.Helper()
+ a := simd.LoadUint64x4Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x8ConvertToUint32(t *testing.T, f func(x simd.Float32x8) simd.Uint32x8, want func(x []float32) []uint32) {
n := 8
t.Helper()
forSlice(t, float32s, n, func(x []float32) bool {
@@ -503,8 +958,84 @@ func testFloat32x8UnaryToUint32(t *testing.T, f func(x simd.Float32x8) simd.Uint
})
}
-// testFloat32x16Unary tests the simd unary method f against the expected behavior generated by want
-func testFloat32x16UnaryToUint32(t *testing.T, f func(x simd.Float32x16) simd.Uint32x16, want func(x []float32) []uint32) {
+// testFloat64x4ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat64x4ConvertToUint32(t *testing.T, f func(x simd.Float64x4) simd.Uint32x4, want func(x []float64) []uint32) {
+ n := 4
+ t.Helper()
+ forSlice(t, float64s, n, func(x []float64) bool {
+ t.Helper()
+ a := simd.LoadFloat64x4Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x16ConvertToUint32(t *testing.T, f func(x simd.Int32x16) simd.Uint32x16, want func(x []int32) []uint32) {
+ n := 16
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x16Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt64x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt64x8ConvertToUint32(t *testing.T, f func(x simd.Int64x8) simd.Uint32x8, want func(x []int64) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, int64s, n, func(x []int64) bool {
+ t.Helper()
+ a := simd.LoadInt64x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x16ConvertToUint32(t *testing.T, f func(x simd.Uint32x16) simd.Uint32x16, want func(x []uint32) []uint32) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x16Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint64x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint64x8ConvertToUint32(t *testing.T, f func(x simd.Uint64x8) simd.Uint32x8, want func(x []uint64) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint64s, n, func(x []uint64) bool {
+ t.Helper()
+ a := simd.LoadUint64x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x16ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x16ConvertToUint32(t *testing.T, f func(x simd.Float32x16) simd.Uint32x16, want func(x []float32) []uint32) {
n := 16
t.Helper()
forSlice(t, float32s, n, func(x []float32) bool {
@@ -517,6 +1048,306 @@ func testFloat32x16UnaryToUint32(t *testing.T, f func(x simd.Float32x16) simd.Ui
})
}
+// testFloat64x8ConvertToUint32 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat64x8ConvertToUint32(t *testing.T, f func(x simd.Float64x8) simd.Uint32x8, want func(x []float64) []uint32) {
+ n := 8
+ t.Helper()
+ forSlice(t, float64s, n, func(x []float64) bool {
+ t.Helper()
+ a := simd.LoadFloat64x8Slice(x)
+ g := make([]uint32, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt8x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt8x16ConvertToUint16(t *testing.T, f func(x simd.Int8x16) simd.Uint16x16, want func(x []int8) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, int8s, n, func(x []int8) bool {
+ t.Helper()
+ a := simd.LoadInt8x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt16x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x8ConvertToUint16(t *testing.T, f func(x simd.Int16x8) simd.Uint16x8, want func(x []int16) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint8x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint8x16ConvertToUint16(t *testing.T, f func(x simd.Uint8x16) simd.Uint16x16, want func(x []uint8) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint8s, n, func(x []uint8) bool {
+ t.Helper()
+ a := simd.LoadUint8x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x8ConvertToUint16(t *testing.T, f func(x simd.Uint16x8) simd.Uint16x8, want func(x []uint16) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt8x32ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt8x32ConvertToUint16(t *testing.T, f func(x simd.Int8x32) simd.Uint16x32, want func(x []int8) []uint16) {
+ n := 32
+ t.Helper()
+ forSlice(t, int8s, n, func(x []int8) bool {
+ t.Helper()
+ a := simd.LoadInt8x32Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt16x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x16ConvertToUint16(t *testing.T, f func(x simd.Int16x16) simd.Uint16x16, want func(x []int16) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x8ConvertToUint16(t *testing.T, f func(x simd.Int32x8) simd.Uint16x8, want func(x []int32) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint8x32ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint8x32ConvertToUint16(t *testing.T, f func(x simd.Uint8x32) simd.Uint16x32, want func(x []uint8) []uint16) {
+ n := 32
+ t.Helper()
+ forSlice(t, uint8s, n, func(x []uint8) bool {
+ t.Helper()
+ a := simd.LoadUint8x32Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x16ConvertToUint16(t *testing.T, f func(x simd.Uint16x16) simd.Uint16x16, want func(x []uint16) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x8ConvertToUint16(t *testing.T, f func(x simd.Uint32x8) simd.Uint16x8, want func(x []uint32) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x8ConvertToUint16(t *testing.T, f func(x simd.Float32x8) simd.Uint16x8, want func(x []float32) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, float32s, n, func(x []float32) bool {
+ t.Helper()
+ a := simd.LoadFloat32x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt16x32ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt16x32ConvertToUint16(t *testing.T, f func(x simd.Int16x32) simd.Uint16x32, want func(x []int16) []uint16) {
+ n := 32
+ t.Helper()
+ forSlice(t, int16s, n, func(x []int16) bool {
+ t.Helper()
+ a := simd.LoadInt16x32Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt32x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt32x16ConvertToUint16(t *testing.T, f func(x simd.Int32x16) simd.Uint16x16, want func(x []int32) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, int32s, n, func(x []int32) bool {
+ t.Helper()
+ a := simd.LoadInt32x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testInt64x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testInt64x8ConvertToUint16(t *testing.T, f func(x simd.Int64x8) simd.Uint16x8, want func(x []int64) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, int64s, n, func(x []int64) bool {
+ t.Helper()
+ a := simd.LoadInt64x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint16x32ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint16x32ConvertToUint16(t *testing.T, f func(x simd.Uint16x32) simd.Uint16x32, want func(x []uint16) []uint16) {
+ n := 32
+ t.Helper()
+ forSlice(t, uint16s, n, func(x []uint16) bool {
+ t.Helper()
+ a := simd.LoadUint16x32Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint32x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint32x16ConvertToUint16(t *testing.T, f func(x simd.Uint32x16) simd.Uint16x16, want func(x []uint32) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, uint32s, n, func(x []uint32) bool {
+ t.Helper()
+ a := simd.LoadUint32x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testUint64x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testUint64x8ConvertToUint16(t *testing.T, f func(x simd.Uint64x8) simd.Uint16x8, want func(x []uint64) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, uint64s, n, func(x []uint64) bool {
+ t.Helper()
+ a := simd.LoadUint64x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat32x16ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat32x16ConvertToUint16(t *testing.T, f func(x simd.Float32x16) simd.Uint16x16, want func(x []float32) []uint16) {
+ n := 16
+ t.Helper()
+ forSlice(t, float32s, n, func(x []float32) bool {
+ t.Helper()
+ a := simd.LoadFloat32x16Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
+// testFloat64x8ConvertToUint16 tests the simd conversion method f against the expected behavior generated by want
+// This is for count-preserving conversions, so if there is a change in size, then there is a change in vector width.
+func testFloat64x8ConvertToUint16(t *testing.T, f func(x simd.Float64x8) simd.Uint16x8, want func(x []float64) []uint16) {
+ n := 8
+ t.Helper()
+ forSlice(t, float64s, n, func(x []float64) bool {
+ t.Helper()
+ a := simd.LoadFloat64x8Slice(x)
+ g := make([]uint16, n)
+ f(a).StoreSlice(g)
+ w := want(x)
+ return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v", x) })
+ })
+}
+
// testFloat32x4UnaryFlaky tests the simd unary method f against the expected behavior generated by want,
// but using a flakiness parameter because we haven't exactly figured out how simd floating point works
func testFloat32x4UnaryFlaky(t *testing.T, f func(x simd.Float32x4) simd.Float32x4, want func(x []float32) []float32, flakiness float64) {
diff --git a/src/simd/unary_test.go b/src/simd/unary_test.go
index 5709ca73c7..6a1d0fe369 100644
--- a/src/simd/unary_test.go
+++ b/src/simd/unary_test.go
@@ -84,11 +84,6 @@ func TestAbsolute(t *testing.T) {
}
}
-func TestToInt32(t *testing.T) {
- testFloat32x4UnaryToInt32(t, simd.Float32x4.ConvertToInt32, toInt32Slice[float32])
- testFloat32x8UnaryToInt32(t, simd.Float32x8.ConvertToInt32, toInt32Slice[float32])
-}
-
func TestCeilScaledResidue(t *testing.T) {
if !simd.HasAVX512() {
t.Skip("Needs AVX512")
@@ -110,7 +105,24 @@ func TestToUint32(t *testing.T) {
if !simd.HasAVX512() {
t.Skip("Needs AVX512")
}
- testFloat32x4UnaryToUint32(t, simd.Float32x4.ConvertToUint32, toUint32Slice[float32])
- testFloat32x8UnaryToUint32(t, simd.Float32x8.ConvertToUint32, toUint32Slice[float32])
- testFloat32x16UnaryToUint32(t, simd.Float32x16.ConvertToUint32, toUint32Slice[float32])
+ testFloat32x4ConvertToUint32(t, simd.Float32x4.ConvertToUint32, map1[float32](toUint32))
+ testFloat32x8ConvertToUint32(t, simd.Float32x8.ConvertToUint32, map1[float32](toUint32))
+ testFloat32x16ConvertToUint32(t, simd.Float32x16.ConvertToUint32, map1[float32](toUint32))
+}
+
+func TestToInt32(t *testing.T) {
+ testFloat32x4ConvertToInt32(t, simd.Float32x4.ConvertToInt32, map1[float32](toInt32))
+ testFloat32x8ConvertToInt32(t, simd.Float32x8.ConvertToInt32, map1[float32](toInt32))
+}
+
+func TestConverts(t *testing.T) {
+ testUint8x16ConvertToUint16(t, simd.Uint8x16.ConvertToUint16, map1[uint8](toUint16))
+ testUint16x8ConvertToUint32(t, simd.Uint16x8.ConvertToUint32, map1[uint16](toUint32))
+}
+
+func TestConvertsAVX512(t *testing.T) {
+ if !simd.HasAVX512() {
+ t.Skip("Needs AVX512")
+ }
+ testUint8x32ConvertToUint16(t, simd.Uint8x32.ConvertToUint16, map1[uint8](toUint16))
}