simd/archsimd: add more tests for Convert operations

For now, only include operations that input and output vectors
have the same number of elements.

Change-Id: If4722f1b0168eaf0e333bdcd218e394fa4ab440f
Reviewed-on: https://go-review.googlesource.com/c/go/+/732662
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Cherry Mui
2025-12-26 16:38:56 -05:00
parent 037c047f2c
commit ca13fe02c4
2 changed files with 120 additions and 21 deletions

View File

@@ -121,16 +121,6 @@ func toUint64[T number](x T) uint64 {
}
func toUint32[T number](x T) uint32 {
switch y := (any(x)).(type) {
case float32:
if y < 0 || y > float32(math.MaxUint32) || y != y {
return math.MaxUint32
}
case float64:
if y < 0 || y > float64(math.MaxUint32) || y != y {
return math.MaxUint32
}
}
return uint32(x)
}
@@ -158,6 +148,74 @@ func toFloat64[T number](x T) float64 {
return float64(x)
}
// X86 specific behavior for conversion from float to int32.
// If the value cannot be represented as int32, it returns -0x80000000.
func floatToInt32_x86[T float](x T) int32 {
switch y := (any(x)).(type) {
case float32:
if y != y || y < math.MinInt32 ||
y >= math.MaxInt32 { // float32(MaxInt32) == 0x80000000, actually overflows
return -0x80000000
}
case float64:
if y != y || y < math.MinInt32 ||
y > math.MaxInt32 { // float64(MaxInt32) is exact, no overflow
return -0x80000000
}
}
return int32(x)
}
// X86 specific behavior for conversion from float to int64.
// If the value cannot be represented as int64, it returns -0x80000000_00000000.
func floatToInt64_x86[T float](x T) int64 {
switch y := (any(x)).(type) {
case float32:
if y != y || y < math.MinInt64 ||
y >= math.MaxInt64 { // float32(MaxInt64) == 0x80000000_00000000, actually overflows
return -0x80000000_00000000
}
case float64:
if y != y || y < math.MinInt64 ||
y >= math.MaxInt64 { // float64(MaxInt64) == 0x80000000_00000000, also overflows
return -0x80000000_00000000
}
}
return int64(x)
}
// X86 specific behavior for conversion from float to uint32.
// If the value cannot be represented as uint32, it returns 1<<32 - 1.
func floatToUint32_x86[T float](x T) uint32 {
switch y := (any(x)).(type) {
case float32:
if y < 0 || y > math.MaxUint32 || y != y {
return 1<<32 - 1
}
case float64:
if y < 0 || y > math.MaxUint32 || y != y {
return 1<<32 - 1
}
}
return uint32(x)
}
// X86 specific behavior for conversion from float to uint64.
// If the value cannot be represented as uint64, it returns 1<<64 - 1.
func floatToUint64_x86[T float](x T) uint64 {
switch y := (any(x)).(type) {
case float32:
if y < 0 || y > math.MaxUint64 || y != y {
return 1<<64 - 1
}
case float64:
if y < 0 || y > math.MaxUint64 || y != y {
return 1<<64 - 1
}
}
return uint64(x)
}
func ceilResidueForPrecision[T float](i int) func(T) T {
f := 1.0
for i > 0 {

View File

@@ -116,18 +116,59 @@ func TestCeilScaledResidue(t *testing.T) {
map1[float64](func(x float64) float64 { return x - math.Ceil(x) }))
}
func TestToUint32(t *testing.T) {
if !archsimd.X86.AVX512() {
t.Skip("Needs AVX512")
}
testFloat32x4ConvertToUint32(t, archsimd.Float32x4.ConvertToUint32, map1[float32](toUint32))
testFloat32x8ConvertToUint32(t, archsimd.Float32x8.ConvertToUint32, map1[float32](toUint32))
testFloat32x16ConvertToUint32(t, archsimd.Float32x16.ConvertToUint32, map1[float32](toUint32))
}
func TestConvert(t *testing.T) {
testFloat32x4ConvertToFloat64(t, archsimd.Float32x4.ConvertToFloat64, map1[float32](toFloat64))
testFloat64x4ConvertToFloat32(t, archsimd.Float64x4.ConvertToFloat32, map1[float64](toFloat32))
func TestToInt32(t *testing.T) {
testFloat32x4ConvertToInt32(t, archsimd.Float32x4.ConvertToInt32, map1[float32](toInt32))
testFloat32x8ConvertToInt32(t, archsimd.Float32x8.ConvertToInt32, map1[float32](toInt32))
testFloat32x4ConvertToInt32(t, archsimd.Float32x4.ConvertToInt32, map1[float32](floatToInt32_x86))
testFloat32x8ConvertToInt32(t, archsimd.Float32x8.ConvertToInt32, map1[float32](floatToInt32_x86))
testFloat64x4ConvertToInt32(t, archsimd.Float64x4.ConvertToInt32, map1[float64](floatToInt32_x86))
testInt32x4ConvertToFloat32(t, archsimd.Int32x4.ConvertToFloat32, map1[int32](toFloat32))
testInt32x4ConvertToFloat64(t, archsimd.Int32x4.ConvertToFloat64, map1[int32](toFloat64))
testInt32x8ConvertToFloat32(t, archsimd.Int32x8.ConvertToFloat32, map1[int32](toFloat32))
if archsimd.X86.AVX512() {
testFloat32x8ConvertToFloat64(t, archsimd.Float32x8.ConvertToFloat64, map1[float32](toFloat64))
testFloat64x8ConvertToFloat32(t, archsimd.Float64x8.ConvertToFloat32, map1[float64](toFloat32))
testFloat32x16ConvertToInt32(t, archsimd.Float32x16.ConvertToInt32, map1[float32](floatToInt32_x86))
testFloat64x8ConvertToInt32(t, archsimd.Float64x8.ConvertToInt32, map1[float64](floatToInt32_x86))
testFloat32x4ConvertToInt64(t, archsimd.Float32x4.ConvertToInt64, map1[float32](floatToInt64_x86))
testFloat32x8ConvertToInt64(t, archsimd.Float32x8.ConvertToInt64, map1[float32](floatToInt64_x86))
testFloat64x2ConvertToInt64(t, archsimd.Float64x2.ConvertToInt64, map1[float64](floatToInt64_x86))
testFloat64x4ConvertToInt64(t, archsimd.Float64x4.ConvertToInt64, map1[float64](floatToInt64_x86))
testFloat64x8ConvertToInt64(t, archsimd.Float64x8.ConvertToInt64, map1[float64](floatToInt64_x86))
testFloat32x4ConvertToUint32(t, archsimd.Float32x4.ConvertToUint32, map1[float32](floatToUint32_x86))
testFloat32x8ConvertToUint32(t, archsimd.Float32x8.ConvertToUint32, map1[float32](floatToUint32_x86))
testFloat32x16ConvertToUint32(t, archsimd.Float32x16.ConvertToUint32, map1[float32](floatToUint32_x86))
testFloat64x4ConvertToUint32(t, archsimd.Float64x4.ConvertToUint32, map1[float64](floatToUint32_x86))
testFloat64x8ConvertToUint32(t, archsimd.Float64x8.ConvertToUint32, map1[float64](floatToUint32_x86))
testFloat32x4ConvertToUint64(t, archsimd.Float32x4.ConvertToUint64, map1[float32](floatToUint64_x86))
testFloat32x8ConvertToUint64(t, archsimd.Float32x8.ConvertToUint64, map1[float32](floatToUint64_x86))
testFloat64x2ConvertToUint64(t, archsimd.Float64x2.ConvertToUint64, map1[float64](floatToUint64_x86))
testFloat64x4ConvertToUint64(t, archsimd.Float64x4.ConvertToUint64, map1[float64](floatToUint64_x86))
testFloat64x8ConvertToUint64(t, archsimd.Float64x8.ConvertToUint64, map1[float64](floatToUint64_x86))
testInt32x16ConvertToFloat32(t, archsimd.Int32x16.ConvertToFloat32, map1[int32](toFloat32))
testInt64x4ConvertToFloat32(t, archsimd.Int64x4.ConvertToFloat32, map1[int64](toFloat32))
testInt64x8ConvertToFloat32(t, archsimd.Int64x8.ConvertToFloat32, map1[int64](toFloat32))
testInt64x2ConvertToFloat64(t, archsimd.Int64x2.ConvertToFloat64, map1[int64](toFloat64))
testInt64x4ConvertToFloat64(t, archsimd.Int64x4.ConvertToFloat64, map1[int64](toFloat64))
testInt64x8ConvertToFloat64(t, archsimd.Int64x8.ConvertToFloat64, map1[int64](toFloat64))
testUint32x4ConvertToFloat32(t, archsimd.Uint32x4.ConvertToFloat32, map1[uint32](toFloat32))
testUint32x8ConvertToFloat32(t, archsimd.Uint32x8.ConvertToFloat32, map1[uint32](toFloat32))
testUint32x16ConvertToFloat32(t, archsimd.Uint32x16.ConvertToFloat32, map1[uint32](toFloat32))
testUint64x4ConvertToFloat32(t, archsimd.Uint64x4.ConvertToFloat32, map1[uint64](toFloat32))
testUint64x8ConvertToFloat32(t, archsimd.Uint64x8.ConvertToFloat32, map1[uint64](toFloat32))
testUint32x4ConvertToFloat64(t, archsimd.Uint32x4.ConvertToFloat64, map1[uint32](toFloat64))
testUint32x8ConvertToFloat64(t, archsimd.Uint32x8.ConvertToFloat64, map1[uint32](toFloat64))
testUint64x2ConvertToFloat64(t, archsimd.Uint64x2.ConvertToFloat64, map1[uint64](toFloat64))
testUint64x4ConvertToFloat64(t, archsimd.Uint64x4.ConvertToFloat64, map1[uint64](toFloat64))
testUint64x8ConvertToFloat64(t, archsimd.Uint64x8.ConvertToFloat64, map1[uint64](toFloat64))
}
}
func TestExtend(t *testing.T) {