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 {