simd: repair missed StorePart-returns-int in generated code added a complete test of the bug that was fixed. Change-Id: I733e928c78d3ffa3236d569e0634f928b97d4586 Reviewed-on: https://go-review.googlesource.com/c/go/+/792101 Auto-Submit: David Chase <drchase@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Junyang Shao <shaojunyang@google.com>
diff --git a/src/simd/archsimd/_gen/tmplgen/main.go b/src/simd/archsimd/_gen/tmplgen/main.go index 772b58e..24ca72a 100644 --- a/src/simd/archsimd/_gen/tmplgen/main.go +++ b/src/simd/archsimd/_gen/tmplgen/main.go
@@ -892,17 +892,18 @@ // StorePart stores the {{.Count}} elements of x into the slice s. // It stores as many elements as will fit in s. // If s has {{.Count}} or more elements, the method is equivalent to x.Store. -func (x {{.VType}}) StorePart(s []{{.Etype}}) { +func (x {{.VType}}) StorePart(s []{{.Etype}}) int { l := len(s) if l >= {{.Count}} { x.Store(s) - return + return {{.Count}} } if l == 0 { - return + return 0 } mask := vecMask{{.EWidth}}[len(vecMask{{.EWidth}})/2-l:] x.StoreArrayMasked(pa{{.VType}}(s), LoadInt{{.WxC}}(mask).asMask()) + return l } `) @@ -924,12 +925,12 @@ // StorePart stores the {{.Count}} elements of x into the slice s. // It stores as many elements as will fit in s. // If s has {{.Count}} or more elements, the method is equivalent to x.Store. -func (x {{.VType}}) StorePart(s []{{.Etype}}) { +func (x {{.VType}}) StorePart(s []{{.Etype}}) int { if len(s) == 0 { - return + return 0 } t := unsafe.Slice((*int{{.EWidth}})(unsafe.Pointer(&s[0])), len(s)) - x.AsInt{{.WxC}}().StorePart(t) + return x.AsInt{{.WxC}}().StorePart(t) } `)
diff --git a/src/simd/archsimd/internal/simd_test/helpers_test.go b/src/simd/archsimd/internal/simd_test/helpers_test.go index 061bb30..c55555b 100644 --- a/src/simd/archsimd/internal/simd_test/helpers_test.go +++ b/src/simd/archsimd/internal/simd_test/helpers_test.go
@@ -9,6 +9,7 @@ import ( "fmt" "math" + "reflect" "simd/archsimd/internal/test_helpers" "testing" "unsafe" @@ -292,3 +293,72 @@ func hideConst[T number](x T) T { return x } + +func testStorePartRV[T number, V any](t *testing.T, name string, n int, val V, storePart func(v V, s []T) int) { + t.Helper() + // empty slice + { + s := make([]T, 0) + rv := storePart(val, s) + if rv != 0 { + t.Errorf("%s: StorePart on empty slice returned %d, expected 0", name, rv) + } + } + + // single-element slice + { + s := make([]T, 1) + rv := storePart(val, s) + if rv != 1 { + t.Errorf("%s: StorePart on 1-element slice returned %d, expected 1", name, rv) + } + } + + // longer-than-vector slice + { + s := make([]T, n+5) + rv := storePart(val, s) + if rv != n { + t.Errorf("%s: StorePart on %d-element slice (longer than %d) returned %d, expected %d", name, n+5, n, rv, n) + } + } +} + +type HasLenAndStorePart[T number] interface { + StorePart(s []T) int + Len() int +} + +func testStorePartReturnValue[T number, V HasLenAndStorePart[T]](t *testing.T) { + t.Helper() + var v V + n := v.Len() + name := reflect.TypeOf(v).Name() + // empty slice + { + s := make([]T, 0) + rv := v.StorePart(s) + if rv != 0 { + t.Errorf("%s: StorePart on empty slice returned %d, expected 0", name, rv) + } + } + + // single-element slice + { + s := make([]T, 1) + rv := v.StorePart(s) + if rv != 1 { + t.Errorf("%s: StorePart on 1-element slice returned %d, expected 1", name, rv) + } + } + + // longer-than-vector slice + { + s := make([]T, n+5) + rv := v.StorePart(s) + if rv != n { + t.Errorf("%s: StorePart on %d-element slice (longer than %d) returned %d, expected %d", name, n+5, n, rv, n) + } + } + t.Logf("tested %s", name) +}
diff --git a/src/simd/archsimd/internal/simd_test/slicepart_128_test.go b/src/simd/archsimd/internal/simd_test/slicepart_128_test.go index 5cb7cff..0e1eda2 100644 --- a/src/simd/archsimd/internal/simd_test/slicepart_128_test.go +++ b/src/simd/archsimd/internal/simd_test/slicepart_128_test.go
@@ -169,3 +169,16 @@ } } } + +func TestStorePartReturnValues128(t *testing.T) { + testStorePartReturnValue[int8, archsimd.Int8x16](t) + testStorePartReturnValue[uint8, archsimd.Uint8x16](t) + testStorePartReturnValue[int16, archsimd.Int16x8](t) + testStorePartReturnValue[uint16, archsimd.Uint16x8](t) + testStorePartReturnValue[int32, archsimd.Int32x4](t) + testStorePartReturnValue[uint32, archsimd.Uint32x4](t) + testStorePartReturnValue[int64, archsimd.Int64x2](t) + testStorePartReturnValue[uint64, archsimd.Uint64x2](t) + testStorePartReturnValue[float32, archsimd.Float32x4](t) + testStorePartReturnValue[float64, archsimd.Float64x2](t) +}
diff --git a/src/simd/archsimd/internal/simd_test/slicepart_wider_test.go b/src/simd/archsimd/internal/simd_test/slicepart_wider_test.go index 58ecb15..dfc3cc6 100644 --- a/src/simd/archsimd/internal/simd_test/slicepart_wider_test.go +++ b/src/simd/archsimd/internal/simd_test/slicepart_wider_test.go
@@ -299,3 +299,31 @@ } } } + +func TestStorePartReturnValuesWider(t *testing.T) { + // AVX2 / 256-bit types + testStorePartReturnValue[int8, archsimd.Int8x32](t) + testStorePartReturnValue[uint8, archsimd.Uint8x32](t) + testStorePartReturnValue[int16, archsimd.Int16x16](t) + testStorePartReturnValue[uint16, archsimd.Uint16x16](t) + testStorePartReturnValue[int32, archsimd.Int32x8](t) + testStorePartReturnValue[uint32, archsimd.Uint32x8](t) + testStorePartReturnValue[int64, archsimd.Int64x4](t) + testStorePartReturnValue[uint64, archsimd.Uint64x4](t) + testStorePartReturnValue[float32, archsimd.Float32x8](t) + testStorePartReturnValue[float64, archsimd.Float64x4](t) + + // AVX512 / 512-bit types + if archsimd.X86.AVX512() { + testStorePartReturnValue[int8, archsimd.Int8x64](t) + testStorePartReturnValue[uint8, archsimd.Uint8x64](t) + testStorePartReturnValue[int16, archsimd.Int16x32](t) + testStorePartReturnValue[uint16, archsimd.Uint16x32](t) + testStorePartReturnValue[int32, archsimd.Int32x16](t) + testStorePartReturnValue[uint32, archsimd.Uint32x16](t) + testStorePartReturnValue[int64, archsimd.Int64x8](t) + testStorePartReturnValue[uint64, archsimd.Uint64x8](t) + testStorePartReturnValue[float32, archsimd.Float32x16](t) + testStorePartReturnValue[float64, archsimd.Float64x8](t) + } +}
diff --git a/src/simd/archsimd/slice_gen_amd64.go b/src/simd/archsimd/slice_gen_amd64.go index 2fddda7..3005809 100644 --- a/src/simd/archsimd/slice_gen_amd64.go +++ b/src/simd/archsimd/slice_gen_amd64.go
@@ -726,17 +726,18 @@ // StorePart stores the 4 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 4 or more elements, the method is equivalent to x.Store. -func (x Int32x4) StorePart(s []int32) { +func (x Int32x4) StorePart(s []int32) int { l := len(s) if l >= 4 { x.Store(s) - return + return 4 } if l == 0 { - return + return 0 } mask := vecMask32[len(vecMask32)/2-l:] x.StoreArrayMasked(paInt32x4(s), LoadInt32x4(mask).asMask()) + return l } // LoadInt64x2Part loads a Int64x2 from the slice s, it returns the loaded vector and the @@ -759,17 +760,18 @@ // StorePart stores the 2 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 2 or more elements, the method is equivalent to x.Store. -func (x Int64x2) StorePart(s []int64) { +func (x Int64x2) StorePart(s []int64) int { l := len(s) if l >= 2 { x.Store(s) - return + return 2 } if l == 0 { - return + return 0 } mask := vecMask64[len(vecMask64)/2-l:] x.StoreArrayMasked(paInt64x2(s), LoadInt64x2(mask).asMask()) + return l } // LoadUint32x4Part loads a Uint32x4 from the slice s, it returns the loaded vector and the @@ -792,17 +794,18 @@ // StorePart stores the 4 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 4 or more elements, the method is equivalent to x.Store. -func (x Uint32x4) StorePart(s []uint32) { +func (x Uint32x4) StorePart(s []uint32) int { l := len(s) if l >= 4 { x.Store(s) - return + return 4 } if l == 0 { - return + return 0 } mask := vecMask32[len(vecMask32)/2-l:] x.StoreArrayMasked(paUint32x4(s), LoadInt32x4(mask).asMask()) + return l } // LoadUint64x2Part loads a Uint64x2 from the slice s, it returns the loaded vector and the @@ -825,17 +828,18 @@ // StorePart stores the 2 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 2 or more elements, the method is equivalent to x.Store. -func (x Uint64x2) StorePart(s []uint64) { +func (x Uint64x2) StorePart(s []uint64) int { l := len(s) if l >= 2 { x.Store(s) - return + return 2 } if l == 0 { - return + return 0 } mask := vecMask64[len(vecMask64)/2-l:] x.StoreArrayMasked(paUint64x2(s), LoadInt64x2(mask).asMask()) + return l } // LoadFloat32x4Part loads a Float32x4 from the slice s, it returns the loaded vector and the @@ -858,17 +862,18 @@ // StorePart stores the 4 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 4 or more elements, the method is equivalent to x.Store. -func (x Float32x4) StorePart(s []float32) { +func (x Float32x4) StorePart(s []float32) int { l := len(s) if l >= 4 { x.Store(s) - return + return 4 } if l == 0 { - return + return 0 } mask := vecMask32[len(vecMask32)/2-l:] x.StoreArrayMasked(paFloat32x4(s), LoadInt32x4(mask).asMask()) + return l } // LoadFloat64x2Part loads a Float64x2 from the slice s, it returns the loaded vector and the @@ -891,17 +896,18 @@ // StorePart stores the 2 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 2 or more elements, the method is equivalent to x.Store. -func (x Float64x2) StorePart(s []float64) { +func (x Float64x2) StorePart(s []float64) int { l := len(s) if l >= 2 { x.Store(s) - return + return 2 } if l == 0 { - return + return 0 } mask := vecMask64[len(vecMask64)/2-l:] x.StoreArrayMasked(paFloat64x2(s), LoadInt64x2(mask).asMask()) + return l } // LoadInt32x8Part loads a Int32x8 from the slice s, it returns the loaded vector and the @@ -924,17 +930,18 @@ // StorePart stores the 8 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 8 or more elements, the method is equivalent to x.Store. -func (x Int32x8) StorePart(s []int32) { +func (x Int32x8) StorePart(s []int32) int { l := len(s) if l >= 8 { x.Store(s) - return + return 8 } if l == 0 { - return + return 0 } mask := vecMask32[len(vecMask32)/2-l:] x.StoreArrayMasked(paInt32x8(s), LoadInt32x8(mask).asMask()) + return l } // LoadInt64x4Part loads a Int64x4 from the slice s, it returns the loaded vector and the @@ -957,17 +964,18 @@ // StorePart stores the 4 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 4 or more elements, the method is equivalent to x.Store. -func (x Int64x4) StorePart(s []int64) { +func (x Int64x4) StorePart(s []int64) int { l := len(s) if l >= 4 { x.Store(s) - return + return 4 } if l == 0 { - return + return 0 } mask := vecMask64[len(vecMask64)/2-l:] x.StoreArrayMasked(paInt64x4(s), LoadInt64x4(mask).asMask()) + return l } // LoadUint32x8Part loads a Uint32x8 from the slice s, it returns the loaded vector and the @@ -990,17 +998,18 @@ // StorePart stores the 8 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 8 or more elements, the method is equivalent to x.Store. -func (x Uint32x8) StorePart(s []uint32) { +func (x Uint32x8) StorePart(s []uint32) int { l := len(s) if l >= 8 { x.Store(s) - return + return 8 } if l == 0 { - return + return 0 } mask := vecMask32[len(vecMask32)/2-l:] x.StoreArrayMasked(paUint32x8(s), LoadInt32x8(mask).asMask()) + return l } // LoadUint64x4Part loads a Uint64x4 from the slice s, it returns the loaded vector and the @@ -1023,17 +1032,18 @@ // StorePart stores the 4 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 4 or more elements, the method is equivalent to x.Store. -func (x Uint64x4) StorePart(s []uint64) { +func (x Uint64x4) StorePart(s []uint64) int { l := len(s) if l >= 4 { x.Store(s) - return + return 4 } if l == 0 { - return + return 0 } mask := vecMask64[len(vecMask64)/2-l:] x.StoreArrayMasked(paUint64x4(s), LoadInt64x4(mask).asMask()) + return l } // LoadFloat32x8Part loads a Float32x8 from the slice s, it returns the loaded vector and the @@ -1056,17 +1066,18 @@ // StorePart stores the 8 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 8 or more elements, the method is equivalent to x.Store. -func (x Float32x8) StorePart(s []float32) { +func (x Float32x8) StorePart(s []float32) int { l := len(s) if l >= 8 { x.Store(s) - return + return 8 } if l == 0 { - return + return 0 } mask := vecMask32[len(vecMask32)/2-l:] x.StoreArrayMasked(paFloat32x8(s), LoadInt32x8(mask).asMask()) + return l } // LoadFloat64x4Part loads a Float64x4 from the slice s, it returns the loaded vector and the @@ -1089,17 +1100,18 @@ // StorePart stores the 4 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 4 or more elements, the method is equivalent to x.Store. -func (x Float64x4) StorePart(s []float64) { +func (x Float64x4) StorePart(s []float64) int { l := len(s) if l >= 4 { x.Store(s) - return + return 4 } if l == 0 { - return + return 0 } mask := vecMask64[len(vecMask64)/2-l:] x.StoreArrayMasked(paFloat64x4(s), LoadInt64x4(mask).asMask()) + return l } // LoadUint8x32Part loads a Uint8x32 from the slice s, it returns the loaded vector and the @@ -1119,12 +1131,12 @@ // StorePart stores the 32 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 32 or more elements, the method is equivalent to x.Store. -func (x Uint8x32) StorePart(s []uint8) { +func (x Uint8x32) StorePart(s []uint8) int { if len(s) == 0 { - return + return 0 } t := unsafe.Slice((*int8)(unsafe.Pointer(&s[0])), len(s)) - x.AsInt8x32().StorePart(t) + return x.AsInt8x32().StorePart(t) } // LoadUint16x16Part loads a Uint16x16 from the slice s, it returns the loaded vector and the @@ -1144,10 +1156,10 @@ // StorePart stores the 16 elements of x into the slice s. // It stores as many elements as will fit in s. // If s has 16 or more elements, the method is equivalent to x.Store. -func (x Uint16x16) StorePart(s []uint16) { +func (x Uint16x16) StorePart(s []uint16) int { if len(s) == 0 { - return + return 0 } t := unsafe.Slice((*int16)(unsafe.Pointer(&s[0])), len(s)) - x.AsInt16x16().StorePart(t) + return x.AsInt16x16().StorePart(t) }
diff --git a/src/simd/internal/bridge/decls_amd64.go b/src/simd/internal/bridge/decls_amd64.go index 7bd1410..5e15dca 100644 --- a/src/simd/internal/bridge/decls_amd64.go +++ b/src/simd/internal/bridge/decls_amd64.go
@@ -1472,12 +1472,12 @@ return (archsimd.Int32x16(x)).StorePart(s) } -func (x Int32x4) StorePart(s []int32) { - (archsimd.Int32x4(x)).StorePart(s) +func (x Int32x4) StorePart(s []int32) int { + return (archsimd.Int32x4(x)).StorePart(s) } -func (x Int32x8) StorePart(s []int32) { - (archsimd.Int32x8(x)).StorePart(s) +func (x Int32x8) StorePart(s []int32) int { + return (archsimd.Int32x8(x)).StorePart(s) } func (x Int32x16) String() string { @@ -1780,12 +1780,12 @@ (archsimd.Int64x8(x)).Store(s) } -func (x Int64x2) StorePart(s []int64) { - (archsimd.Int64x2(x)).StorePart(s) +func (x Int64x2) StorePart(s []int64) int { + return (archsimd.Int64x2(x)).StorePart(s) } -func (x Int64x4) StorePart(s []int64) { - (archsimd.Int64x4(x)).StorePart(s) +func (x Int64x4) StorePart(s []int64) int { + return (archsimd.Int64x4(x)).StorePart(s) } func (x Int64x8) StorePart(s []int64) int { @@ -2108,8 +2108,8 @@ return (archsimd.Uint8x16(x)).StorePart(s) } -func (x Uint8x32) StorePart(s []uint8) { - (archsimd.Uint8x32(x)).StorePart(s) +func (x Uint8x32) StorePart(s []uint8) int { + return (archsimd.Uint8x32(x)).StorePart(s) } func (x Uint8x64) StorePart(s []uint8) int { @@ -2512,8 +2512,8 @@ (archsimd.Uint16x8(x)).Store(s) } -func (x Uint16x16) StorePart(s []uint16) { - (archsimd.Uint16x16(x)).StorePart(s) +func (x Uint16x16) StorePart(s []uint16) int { + return (archsimd.Uint16x16(x)).StorePart(s) } func (x Uint16x32) StorePart(s []uint16) int { @@ -2912,12 +2912,12 @@ return (archsimd.Uint32x16(x)).StorePart(s) } -func (x Uint32x4) StorePart(s []uint32) { - (archsimd.Uint32x4(x)).StorePart(s) +func (x Uint32x4) StorePart(s []uint32) int { + return (archsimd.Uint32x4(x)).StorePart(s) } -func (x Uint32x8) StorePart(s []uint32) { - (archsimd.Uint32x8(x)).StorePart(s) +func (x Uint32x8) StorePart(s []uint32) int { + return (archsimd.Uint32x8(x)).StorePart(s) } func (x Uint32x16) String() string { @@ -3280,12 +3280,12 @@ (archsimd.Uint64x8(x)).Store(s) } -func (x Uint64x2) StorePart(s []uint64) { - (archsimd.Uint64x2(x)).StorePart(s) +func (x Uint64x2) StorePart(s []uint64) int { + return (archsimd.Uint64x2(x)).StorePart(s) } -func (x Uint64x4) StorePart(s []uint64) { - (archsimd.Uint64x4(x)).StorePart(s) +func (x Uint64x4) StorePart(s []uint64) int { + return (archsimd.Uint64x4(x)).StorePart(s) } func (x Uint64x8) StorePart(s []uint64) int { @@ -3572,12 +3572,12 @@ return (archsimd.Float32x16(x)).StorePart(s) } -func (x Float32x4) StorePart(s []float32) { - (archsimd.Float32x4(x)).StorePart(s) +func (x Float32x4) StorePart(s []float32) int { + return (archsimd.Float32x4(x)).StorePart(s) } -func (x Float32x8) StorePart(s []float32) { - (archsimd.Float32x8(x)).StorePart(s) +func (x Float32x8) StorePart(s []float32) int { + return (archsimd.Float32x8(x)).StorePart(s) } func (x Float32x16) String() string { @@ -3844,12 +3844,12 @@ (archsimd.Float64x8(x)).Store(s) } -func (x Float64x2) StorePart(s []float64) { - (archsimd.Float64x2(x)).StorePart(s) +func (x Float64x2) StorePart(s []float64) int { + return (archsimd.Float64x2(x)).StorePart(s) } -func (x Float64x4) StorePart(s []float64) { - (archsimd.Float64x4(x)).StorePart(s) +func (x Float64x4) StorePart(s []float64) int { + return (archsimd.Float64x4(x)).StorePart(s) } func (x Float64x8) StorePart(s []float64) int {