From ca13fe02c48db993a34d441d87180cf665d5b288 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 26 Dec 2025 16:38:56 -0500 Subject: [PATCH] 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 LUCI-TryBot-Result: Go LUCI --- .../simd_test/simulation_helpers_test.go | 78 ++++++++++++++++--- .../archsimd/internal/simd_test/unary_test.go | 63 ++++++++++++--- 2 files changed, 120 insertions(+), 21 deletions(-) diff --git a/src/simd/archsimd/internal/simd_test/simulation_helpers_test.go b/src/simd/archsimd/internal/simd_test/simulation_helpers_test.go index 2f040ffb3e..a51912a47f 100644 --- a/src/simd/archsimd/internal/simd_test/simulation_helpers_test.go +++ b/src/simd/archsimd/internal/simd_test/simulation_helpers_test.go @@ -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 { diff --git a/src/simd/archsimd/internal/simd_test/unary_test.go b/src/simd/archsimd/internal/simd_test/unary_test.go index 9110a6eac6..561709841d 100644 --- a/src/simd/archsimd/internal/simd_test/unary_test.go +++ b/src/simd/archsimd/internal/simd_test/unary_test.go @@ -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) { -- 2.52.0