From af6475df7338155cf6bfca2caf3686b7f8b2f2e2 Mon Sep 17 00:00:00 2001 From: David Chase Date: Tue, 19 Aug 2025 15:26:19 -0400 Subject: [PATCH] [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 Reviewed-by: Junyang Shao TryBot-Bypass: David Chase --- src/simd/genfiles.go | 98 ++-- src/simd/simulation_helpers_test.go | 46 +- src/simd/unary_helpers_test.go | 869 +++++++++++++++++++++++++++- src/simd/unary_test.go | 28 +- 4 files changed, 969 insertions(+), 72 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,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) { 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)) } -- 2.52.0