]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.simd] simd: add testing hooks for size-changing conversions
authorDavid Chase <drchase@google.com>
Tue, 19 Aug 2025 19:26:19 +0000 (15:26 -0400)
committerDavid Chase <drchase@google.com>
Wed, 20 Aug 2025 22:10:27 +0000 (15:10 -0700)
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>

src/simd/genfiles.go
src/simd/simulation_helpers_test.go
src/simd/unary_helpers_test.go
src/simd/unary_test.go

index be149ef637ce3f27ed1b2f26f736693ad18674b6..3d9b26a6b00e3d0365d227da8bbff1970582de7b 100644 (file)
@@ -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)
index 8677216d9fa2c4c0da35b27a8f4941de1ca8df27..2f040ffb3e71d39806fa43b4f9987c8c07e7c29e 100644 (file)
@@ -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)
-}
index f5b9e3b676b21efc9d7f57a54cfdb29267a26f72..d99fd3c505419121f2291c525c25f1bf4ec0cc74 100644 (file)
@@ -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,13 +733,29 @@ 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) {
-       n := 4
+// 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, float32s, n, func(x []float32) bool {
+       forSlice(t, float64s, n, func(x []float64) bool {
                t.Helper()
-               a := simd.LoadFloat32x4Slice(x)
+               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)
@@ -489,13 +763,14 @@ 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) {
+// 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, float32s, n, func(x []float32) bool {
+       forSlice(t, int16s, n, func(x []int16) bool {
                t.Helper()
-               a := simd.LoadFloat32x8Slice(x)
+               a := simd.LoadInt16x8Slice(x)
                g := make([]uint32, n)
                f(a).StoreSlice(g)
                w := want(x)
@@ -503,13 +778,29 @@ 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) {
+// 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, float32s, n, func(x []float32) bool {
+       forSlice(t, uint8s, n, func(x []uint8) bool {
                t.Helper()
-               a := simd.LoadFloat32x16Slice(x)
+               a := simd.LoadUint8x16Slice(x)
                g := make([]uint32, n)
                f(a).StoreSlice(g)
                w := want(x)
@@ -517,6 +808,546 @@ func testFloat32x16UnaryToUint32(t *testing.T, f func(x simd.Float32x16) simd.Ui
        })
 }
 
+// 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 {
+               t.Helper()
+               a := simd.LoadFloat32x4Slice(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) })
+       })
+}
+
+// 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 {
+               t.Helper()
+               a := simd.LoadFloat32x8Slice(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) })
+       })
+}
+
+// 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 {
+               t.Helper()
+               a := simd.LoadFloat32x16Slice(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) })
+       })
+}
+
+// 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) {
index 5709ca73c7e7ad5453c45bef2dabfc0fc83db47b..6a1d0fe36981612765904c5e6df81ced2c0a5558 100644 (file)
@@ -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))
 }