diff --git a/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj b/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj index e956491c0a63b1..5d98f157e174a3 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj +++ b/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs new file mode 100644 index 00000000000000..b3694d7e8cf771 --- /dev/null +++ b/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs @@ -0,0 +1,524 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Wasm; +using System.Tests; +using Xunit; + +namespace System.Runtime.Intrinsics.Wasm.Tests +{ + [PlatformSpecific(TestPlatforms.Browser)] + public sealed class PackedSimdTests + { + [Fact] + public unsafe void BasicArithmeticTest() + { + var v1 = Vector128.Create(1, 2, 3, 4); + var v2 = Vector128.Create(5, 6, 7, 8); + + var addResult = PackedSimd.Add(v1, v2); + var subResult = PackedSimd.Subtract(v1, v2); + var mulResult = PackedSimd.Multiply(v1, v2); + + Assert.Equal(Vector128.Create(6, 8, 10, 12), addResult); + Assert.Equal(Vector128.Create(-4, -4, -4, -4), subResult); + Assert.Equal(Vector128.Create(5, 12, 21, 32), mulResult); + } + + [Fact] + public unsafe void BitwiseOperationsTest() + { + var v1 = Vector128.Create(0b1100, 0b1010, 0b1110, 0b1111); + var v2 = Vector128.Create(0b1010, 0b1100, 0b0011, 0b0101); + + var andResult = PackedSimd.And(v1, v2); + var orResult = PackedSimd.Or(v1, v2); + var xorResult = PackedSimd.Xor(v1, v2); + + Assert.Equal(Vector128.Create(0b1000, 0b1000, 0b0010, 0b0101), andResult); + Assert.Equal(Vector128.Create(0b1110, 0b1110, 0b1111, 0b1111), orResult); + Assert.Equal(Vector128.Create(0b0110, 0b0110, 0b1101, 0b1010), xorResult); + } + + [Fact] + public unsafe void ShiftOperationsTest() + { + var v = Vector128.Create(16, -16, 32, -32); + + var leftShift = PackedSimd.ShiftLeft(v, 2); + var rightShiftArith = PackedSimd.ShiftRightArithmetic(v, 2); + var rightShiftLogical = PackedSimd.ShiftRightLogical(v, 2); + + Assert.Equal(Vector128.Create(64, -64, 128, -128), leftShift); + Assert.Equal(Vector128.Create(4, -4, 8, -8), rightShiftArith); + Assert.Equal(Vector128.Create(4, 1073741820, 8, 1073741816), rightShiftLogical); + } + + [Fact] + public unsafe void ComparisonOperationsTest() + { + var v1 = Vector128.Create(1.0f, 2.0f, 3.0f, 4.0f); + var v2 = Vector128.Create(4.0f, 3.0f, 2.0f, 1.0f); + + var minResult = PackedSimd.Min(v1, v2); + var maxResult = PackedSimd.Max(v1, v2); + + Assert.Equal(Vector128.Create(1.0f, 2.0f, 2.0f, 1.0f), minResult); + Assert.Equal(Vector128.Create(4.0f, 3.0f, 3.0f, 4.0f), maxResult); + } + + [Fact] + public unsafe void FloatingPointOperationsTest() + { + var v = Vector128.Create(4.0f, 9.0f, 16.0f, 25.0f); + + var sqrtResult = PackedSimd.Sqrt(v); + var ceilResult = PackedSimd.Ceiling(v); + var floorResult = PackedSimd.Floor(v); + + Assert.Equal(Vector128.Create(2.0f, 3.0f, 4.0f, 5.0f), sqrtResult); + Assert.Equal(Vector128.Create(4.0f, 9.0f, 16.0f, 25.0f), ceilResult); + Assert.Equal(Vector128.Create(4.0f, 9.0f, 16.0f, 25.0f), floorResult); + } + + [Fact] + public unsafe void LoadStoreTest() + { + int[] values = new int[] { 1, 2, 3, 4 }; + fixed (int* ptr = values) + { + var loaded = PackedSimd.LoadVector128(ptr); + Assert.Equal(Vector128.Create(1, 2, 3, 4), loaded); + + int[] storeTarget = new int[4]; + fixed (int* storePtr = storeTarget) + { + PackedSimd.Store(storePtr, loaded); + Assert.Equal(values, storeTarget); + } + } + } + + [Fact] + public unsafe void ExtractInsertScalarTest() + { + var v = Vector128.Create(1, 2, 3, 4); + + int extracted = PackedSimd.ExtractScalar(v, 2); + Assert.Equal(3, extracted); + + var modified = PackedSimd.ReplaceScalar(v, 2, 10); + Assert.Equal(Vector128.Create(1, 2, 10, 4), modified); + } + + [Fact] + public unsafe void SaturatingArithmeticTest() + { + var v1 = Vector128.Create((byte)250, (byte)251, (byte)252, (byte)253, (byte)254, (byte)255, (byte)255, (byte)255, + (byte)250, (byte)251, (byte)252, (byte)253, (byte)254, (byte)255, (byte)255, (byte)255); + var v2 = Vector128.Create((byte)10, (byte)10, (byte)10, (byte)10, (byte)10, (byte)10, (byte)10, (byte)10, + (byte)10, (byte)10, (byte)10, (byte)10, (byte)10, (byte)10, (byte)10, (byte)10); + + var addSat = PackedSimd.AddSaturate(v1, v2); + var subSat = PackedSimd.SubtractSaturate(v1, v2); + + // Verify saturation at 255 for addition + Assert.Equal(Vector128.Create((byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, + (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255), addSat); + + // Verify expected subtraction results + Assert.Equal(Vector128.Create((byte)240, (byte)241, (byte)242, (byte)243, (byte)244, (byte)245, (byte)245, (byte)245, + (byte)240, (byte)241, (byte)242, (byte)243, (byte)244, (byte)245, (byte)245, (byte)245), subSat); + } + + [Fact] + public unsafe void WideningOperationsTest() + { + var v = Vector128.Create((short)1000, (short)2000, (short)3000, (short)4000, + (short)5000, (short)6000, (short)7000, (short)8000); + + var lowerWidened = PackedSimd.SignExtendWideningLower(v); + var upperWidened = PackedSimd.SignExtendWideningUpper(v); + + Assert.Equal(Vector128.Create(1000, 2000, 3000, 4000), lowerWidened); + Assert.Equal(Vector128.Create(5000, 6000, 7000, 8000), upperWidened); + } + + [Fact] + public unsafe void SwizzleTest() + { + var v = Vector128.Create((byte)1, (byte)2, (byte)3, (byte)4, (byte)5, (byte)6, (byte)7, (byte)8, + (byte)9, (byte)10, (byte)11, (byte)12, (byte)13, (byte)14, (byte)15, (byte)16); + var indices = Vector128.Create((byte)3, (byte)2, (byte)1, (byte)0, (byte)7, (byte)6, (byte)5, (byte)4, + (byte)11, (byte)10, (byte)9, (byte)8, (byte)15, (byte)14, (byte)13, (byte)12); + + var swizzled = PackedSimd.Swizzle(v, indices); + + Assert.Equal(Vector128.Create((byte)4, (byte)3, (byte)2, (byte)1, (byte)8, (byte)7, (byte)6, (byte)5, + (byte)12, (byte)11, (byte)10, (byte)9, (byte)16, (byte)15, (byte)14, (byte)13), swizzled); + } + + [Fact] + public unsafe void LoadScalarAndSplatTest() + { + int value = 42; + float fValue = 3.14f; + + int* intPtr = &value; + float* floatPtr = &fValue; + + var intSplat = PackedSimd.LoadScalarAndSplatVector128(intPtr); + var floatSplat = PackedSimd.LoadScalarAndSplatVector128(floatPtr); + + Assert.Equal(Vector128.Create(42, 42, 42, 42), intSplat); + Assert.Equal(Vector128.Create(3.14f, 3.14f, 3.14f, 3.14f), floatSplat); + } + + [Fact] + public unsafe void LoadWideningTest() + { + byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + fixed (byte* ptr = bytes) + { + var widened = PackedSimd.LoadWideningVector128(ptr); + Assert.Equal(Vector128.Create((ushort)1, (ushort)2, (ushort)3, (ushort)4, + (ushort)5, (ushort)6, (ushort)7, (ushort)8), widened); + } + } + + [Fact] + public unsafe void StoreSelectedScalarTest() + { + var v = Vector128.Create(1, 2, 3, 4); + int value = 0; + int* ptr = &value; + + PackedSimd.StoreSelectedScalar(ptr, v, 2); + Assert.Equal(3, value); + } + + [Fact] + public unsafe void LoadScalarAndInsertTest() + { + var v = Vector128.Create(1, 2, 3, 4); + int newValue = 42; + int* ptr = &newValue; + + var result = PackedSimd.LoadScalarAndInsert(ptr, v, 2); + Assert.Equal(Vector128.Create(1, 2, 42, 4), result); + } + + [Fact] + public unsafe void ConversionTest() + { + var intVector = Vector128.Create(1, 2, 3, 4); + var floatVector = Vector128.Create(1.5f, 2.5f, 3.5f, 4.5f); + var doubleVector = Vector128.Create(1.5, 2.5); + + var intToFloat = PackedSimd.ConvertToSingle(intVector); + var floatToDouble = PackedSimd.ConvertToDoubleLower(floatVector); + + Assert.Equal(Vector128.Create(1.0f, 2.0f, 3.0f, 4.0f), intToFloat); + Assert.Equal(Vector128.Create(1.5, 2.5), floatToDouble); + } + + [Fact] + public unsafe void AddPairwiseWideningTest() + { + var bytes = Vector128.Create((byte)1, (byte)2, (byte)3, (byte)4, + (byte)5, (byte)6, (byte)7, (byte)8, + (byte)9, (byte)10, (byte)11, (byte)12, + (byte)13, (byte)14, (byte)15, (byte)16); + + var widened = PackedSimd.AddPairwiseWidening(bytes); + + Assert.Equal(Vector128.Create((ushort)3, (ushort)7, (ushort)11, (ushort)15, + (ushort)19, (ushort)23, (ushort)27, (ushort)31), widened); + } + + [Fact] + public unsafe void MultiplyWideningTest() + { + var shorts = Vector128.Create((short)10, (short)20, (short)30, (short)40, + (short)50, (short)60, (short)70, (short)80); + var multiplier = Vector128.Create((short)2, (short)2, (short)2, (short)2, + (short)2, (short)2, (short)2, (short)2); + + var lowerResult = PackedSimd.MultiplyWideningLower(shorts, multiplier); + var upperResult = PackedSimd.MultiplyWideningUpper(shorts, multiplier); + + Assert.Equal(Vector128.Create(20, 40, 60, 80), lowerResult); + Assert.Equal(Vector128.Create(100, 120, 140, 160), upperResult); + } + + [Fact] + public unsafe void DotProductTest() + { + var v1 = Vector128.Create((short)1, (short)2, (short)3, (short)4, + (short)5, (short)6, (short)7, (short)8); + var v2 = Vector128.Create((short)2, (short)2, (short)2, (short)2, + (short)2, (short)2, (short)2, (short)2); + + var dot = PackedSimd.Dot(v1, v2); + + // Each pair of values is multiplied and added: + // (1*2 + 2*2) = 6 for first int + // (3*2 + 4*2) = 14 for second int + // (5*2 + 6*2) = 22 for third int + // (7*2 + 8*2) = 30 for fourth int + Assert.Equal(Vector128.Create(6, 14, 22, 30), dot); + } + + [Fact] + public unsafe void FloatingPointNegationTest() + { + var v = Vector128.Create(1.0f, -2.0f, 3.0f, -4.0f); + var d = Vector128.Create(1.0, -2.0); + + var negatedFloat = PackedSimd.Negate(v); + var negatedDouble = PackedSimd.Negate(d); + + Assert.Equal(Vector128.Create(-1.0f, 2.0f, -3.0f, 4.0f), negatedFloat); + Assert.Equal(Vector128.Create(-1.0, 2.0), negatedDouble); + } + + [Fact] + public unsafe void FloatingPointAbsTest() + { + var v = Vector128.Create(-1.0f, 2.0f, -3.0f, 4.0f); + var d = Vector128.Create(-1.0, 2.0); + + var absFloat = PackedSimd.Abs(v); + var absDouble = PackedSimd.Abs(d); + + Assert.Equal(Vector128.Create(1.0f, 2.0f, 3.0f, 4.0f), absFloat); + Assert.Equal(Vector128.Create(1.0, 2.0), absDouble); + } + + [Fact] + public unsafe void FloatingPointDivisionTest() + { + var v1 = Vector128.Create(2.0f, 4.0f, 6.0f, 8.0f); + var v2 = Vector128.Create(2.0f, 2.0f, 2.0f, 2.0f); + var d1 = Vector128.Create(2.0, 4.0); + var d2 = Vector128.Create(2.0, 2.0); + + var divFloat = PackedSimd.Divide(v1, v2); + var divDouble = PackedSimd.Divide(d1, d2); + + Assert.Equal(Vector128.Create(1.0f, 2.0f, 3.0f, 4.0f), divFloat); + Assert.Equal(Vector128.Create(1.0, 2.0), divDouble); + } + + [Fact] + public unsafe void IntegerAbsTest() + { + var bytes = Vector128.Create((sbyte)-1, (sbyte)2, (sbyte)-3, (sbyte)4, + (sbyte)-5, (sbyte)6, (sbyte)-7, (sbyte)8, + (sbyte)-9, (sbyte)10, (sbyte)-11, (sbyte)12, + (sbyte)-13, (sbyte)14, (sbyte)-15, (sbyte)16); + var shorts = Vector128.Create((short)-1, (short)2, (short)-3, (short)4, + (short)-5, (short)6, (short)-7, (short)8); + var ints = Vector128.Create(-1, 2, -3, 4); + + var absBytes = PackedSimd.Abs(bytes); + var absShorts = PackedSimd.Abs(shorts); + + Assert.Equal(Vector128.Create((sbyte)1, (sbyte)2, (sbyte)3, (sbyte)4, + (sbyte)5, (sbyte)6, (sbyte)7, (sbyte)8, + (sbyte)9, (sbyte)10, (sbyte)11, (sbyte)12, + (sbyte)13, (sbyte)14, (sbyte)15, (sbyte)16), absBytes); + Assert.Equal(Vector128.Create((short)1, (short)2, (short)3, (short)4, + (short)5, (short)6, (short)7, (short)8), absShorts); + } + + [Fact] + public unsafe void AverageRoundedTest() + { + var bytes1 = Vector128.Create((byte)1, (byte)3, (byte)5, (byte)7, + (byte)9, (byte)11, (byte)13, (byte)15, + (byte)17, (byte)19, (byte)21, (byte)23, + (byte)25, (byte)27, (byte)29, (byte)31); + var bytes2 = Vector128.Create((byte)3, (byte)5, (byte)7, (byte)9, + (byte)11, (byte)13, (byte)15, (byte)17, + (byte)19, (byte)21, (byte)23, (byte)25, + (byte)27, (byte)29, (byte)31, (byte)33); + + var avgBytes = PackedSimd.AverageRounded(bytes1, bytes2); + + // Average is rounded up: (a + b + 1) >> 1 + Assert.Equal(Vector128.Create((byte)2, (byte)4, (byte)6, (byte)8, + (byte)10, (byte)12, (byte)14, (byte)16, + (byte)18, (byte)20, (byte)22, (byte)24, + (byte)26, (byte)28, (byte)30, (byte)32), avgBytes); + } + + [Fact] + public unsafe void MinMaxSignedUnsignedTest() + { + var signedBytes = Vector128.Create((sbyte)-1, (sbyte)2, (sbyte)-3, (sbyte)4, + (sbyte)-5, (sbyte)6, (sbyte)-7, (sbyte)8, + (sbyte)-9, (sbyte)10, (sbyte)-11, (sbyte)12, + (sbyte)-13, (sbyte)14, (sbyte)-15, (sbyte)16); + + var unsignedBytes = Vector128.Create((byte)255, (byte)2, (byte)253, (byte)4, + (byte)251, (byte)6, (byte)249, (byte)8, + (byte)247, (byte)10, (byte)245, (byte)12, + (byte)243, (byte)14, (byte)241, (byte)16); + + var signedMin = PackedSimd.Min(signedBytes, signedBytes.WithElement(0, (sbyte)0)); + var unsignedMin = PackedSimd.Min(unsignedBytes, unsignedBytes.WithElement(0, (byte)0)); + + // Verify different comparison behavior for signed vs unsigned + Assert.Equal((sbyte)-1, signedMin.GetElement(0)); + Assert.Equal((byte)0, unsignedMin.GetElement(0)); + } + + [Fact] + public unsafe void LoadScalarAndSplatInfinityTest() + { + float fInf = float.PositiveInfinity; + double dInf = double.PositiveInfinity; + + float* fPtr = &fInf; + double* dPtr = &dInf; + + var floatSplat = PackedSimd.LoadScalarAndSplatVector128(fPtr); + var doubleSplat = PackedSimd.LoadScalarAndSplatVector128(dPtr); + + for (int i = 0; i < 4; i++) + { + Assert.True(float.IsPositiveInfinity(floatSplat.GetElement(i))); + } + + for (int i = 0; i < 2; i++) + { + Assert.True(double.IsPositiveInfinity(doubleSplat.GetElement(i))); + } + } + + [Fact] + public unsafe void FloatingPointTruncateTest() + { + var v1 = Vector128.Create(1.7f, -2.3f, 3.5f, -4.8f); + var d1 = Vector128.Create(1.7, -2.3); + + var truncFloat = PackedSimd.Truncate(v1); + var truncDouble = PackedSimd.Truncate(d1); + + Assert.Equal(Vector128.Create(1.0f, -2.0f, 3.0f, -4.0f), truncFloat); + Assert.Equal(Vector128.Create(1.0, -2.0), truncDouble); + } + + [Fact] + public unsafe void ComparisonWithNaNTest() + { + var v1 = Vector128.Create(1.0f, float.NaN, 3.0f, float.PositiveInfinity); + var v2 = Vector128.Create(float.NegativeInfinity, 2.0f, float.NaN, 4.0f); + + var minResult = PackedSimd.Min(v1, v2); + var maxResult = PackedSimd.Max(v1, v2); + + // IEEE 754 rules: if either operand is NaN, the result should be NaN + Assert.True(float.IsNaN(minResult.GetElement(1))); + Assert.True(float.IsNaN(maxResult.GetElement(2))); + Assert.Equal(float.NegativeInfinity, minResult.GetElement(0)); + Assert.Equal(float.PositiveInfinity, maxResult.GetElement(3)); + } + + [Fact] + public unsafe void NativeIntegerArithmeticTest() + { + var v1 = Vector128.Create([(nint)1, (nint)2, (nint)3, (nint)4]); + var v2 = Vector128.Create([(nint)5, (nint)6, (nint)7, (nint)8]); + + var addResult = PackedSimd.Add(v1, v2); + var subResult = PackedSimd.Subtract(v1, v2); + var mulResult = PackedSimd.Multiply(v1, v2); + + Assert.Equal(Vector128.Create([(nint)6, (nint)8, (nint)10, (nint)12]), addResult); + Assert.Equal(Vector128.Create([(nint)(-4), (nint)(-4), (nint)(-4), (nint)(-4)]), subResult); + Assert.Equal(Vector128.Create([(nint)5, (nint)12, (nint)21, (nint)32]), mulResult); + } + + [Fact] + public unsafe void NativeUnsignedIntegerArithmeticTest() + { + var v1 = Vector128.Create([(nuint)1, (nuint)2, (nuint)3, (nuint)4]); + var v2 = Vector128.Create([(nuint)5, (nuint)6, (nuint)7, (nuint)8]); + + var addResult = PackedSimd.Add(v1, v2); + var subResult = PackedSimd.Subtract(v1, v2); + var mulResult = PackedSimd.Multiply(v1, v2); + + Assert.Equal(Vector128.Create([(nuint)6, (nuint)8, (nuint)10, (nuint)12]), addResult); + Assert.Equal(Vector128.Create([unchecked((nuint)(-4)), unchecked((nuint)(-4)), unchecked((nuint)(-4)), unchecked((nuint)(-4))]), subResult); + Assert.Equal(Vector128.Create([(nuint)5, (nuint)12, (nuint)21, (nuint)32]), mulResult); + } + + [Fact] + public unsafe void NativeIntegerLoadStoreTest() + { + nint[] values = new nint[] { 1, 2, 3, 4 }; + fixed (nint* ptr = values) + { + var loaded = PackedSimd.LoadVector128(ptr); + Assert.Equal(Vector128.Create(values.AsSpan()), loaded); + + nint[] storeTarget = new nint[4]; + fixed (nint* storePtr = storeTarget) + { + PackedSimd.Store(storePtr, loaded); + Assert.Equal(values, storeTarget); + } + } + } + + [Fact] + public unsafe void NativeUnsignedIntegerLoadStoreTest() + { + nuint[] values = new nuint[] { 1, 2, 3, 4 }; + fixed (nuint* ptr = values) + { + var loaded = PackedSimd.LoadVector128(ptr); + Assert.Equal(Vector128.Create(values.AsSpan()), loaded); + + nuint[] storeTarget = new nuint[4]; + fixed (nuint* storePtr = storeTarget) + { + PackedSimd.Store(storePtr, loaded); + Assert.Equal(values, storeTarget); + } + } + } + + [Fact] + public void NativeIntegerShiftTest() + { + var v = Vector128.Create([(nint)16, (nint)(-16), (nint)32, (nint)(-32)]); + + var leftShift = PackedSimd.ShiftLeft(v, 2); + var rightShiftArith = PackedSimd.ShiftRightArithmetic(v, 2); + var rightShiftLogical = PackedSimd.ShiftRightLogical(v, 2); + + Assert.Equal(Vector128.Create([(nint)64, (nint)(-64), (nint)128, (nint)(-128)]), leftShift); + Assert.Equal(Vector128.Create([(nint)4, (nint)(-4), (nint)8, (nint)(-8)]), rightShiftArith); + Assert.Equal(Vector128.Create([(nint)4, (nint)1073741820, (nint)8, (nint)1073741816]), rightShiftLogical); + } + + [Fact] + public void NativeUnsignedIntegerShiftTest() + { + var v = Vector128.Create([(nuint)16, unchecked((nuint)(-16)), (nuint)32, unchecked((nuint)(-32))]); + + var leftShift = PackedSimd.ShiftLeft(v, 2); + var rightShiftLogical = PackedSimd.ShiftRightLogical(v, 2); + + Assert.Equal(Vector128.Create([(nuint)64, unchecked((nuint)(-64)), (nuint)128, unchecked((nuint)(-128))]), leftShift); + Assert.Equal(Vector128.Create([(nuint)4, (nuint)1073741820, (nuint)8, (nuint)1073741816]), rightShiftLogical); + } + } +} \ No newline at end of file diff --git a/src/mono/mono/mini/interp/interp-simd-intrins.def b/src/mono/mono/mini/interp/interp-simd-intrins.def index d88e543af23471..197b3c269d6612 100644 --- a/src/mono/mono/mini/interp/interp-simd-intrins.def +++ b/src/mono/mono/mini/interp/interp-simd-intrins.def @@ -351,7 +351,7 @@ INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToSingle, U4, wasm_f32x4_convert_u32x4, INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToSingle, R8, wasm_f32x4_demote_f64x2_zero, 0x5e) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, I4, wasm_f64x2_convert_low_i32x4, 0xfe) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, U4, wasm_f64x2_convert_low_u32x4, 0xff) -INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, R8, wasm_f64x2_promote_low_f32x4, 0x5f) +INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, R4, wasm_f64x2_promote_low_f32x4, 0x5f) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToInt32Saturate, R4, wasm_i32x4_trunc_sat_f32x4, 0xf8) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToUInt32Saturate, R4, wasm_u32x4_trunc_sat_f32x4, 0xf9) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToInt32Saturate, R8, wasm_i32x4_trunc_sat_f64x2_zero, 0xfc) diff --git a/src/mono/mono/mini/interp/transform-simd.c b/src/mono/mono/mini/interp/transform-simd.c index 7a56b6e90ab87d..3ef90289648614 100644 --- a/src/mono/mono/mini/interp/transform-simd.c +++ b/src/mono/mono/mini/interp/transform-simd.c @@ -162,10 +162,29 @@ static guint16 sri_packedsimd_methods [] = { SN_get_IsSupported, }; +static MonoTypeEnum +resolve_native_size (MonoTypeEnum type) +{ + if (type == MONO_TYPE_I) +#if TARGET_SIZEOF_VOID_P == 4 + return MONO_TYPE_I4; +#else + return MONO_TYPE_I8; +#endif + else if (type == MONO_TYPE_U) +#if TARGET_SIZEOF_VOID_P == 4 + return MONO_TYPE_U4; +#else + return MONO_TYPE_U8; +#endif + return type; + +} // Returns if opcode was added static gboolean emit_common_simd_operations (TransformData *td, int id, int atype, int vector_size, int arg_size, int scalar_arg, gint16 *simd_opcode, gint16 *simd_intrins) { + atype = resolve_native_size (atype); switch (id) { case SN_get_AllBitsSet: { interp_add_ins (td, MINT_SIMD_V128_LDC); @@ -563,6 +582,7 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature else if (arg_size == 8) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_CREATE_SCALAR; break; case SN_Equals: + atype = resolve_native_size (atype); simd_opcode = MINT_SIMD_INTRINS_P_PP; if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_EQUALS; else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_EQUALS; @@ -571,6 +591,7 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature else if (atype == MONO_TYPE_R4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_EQUALS; break; case SN_EqualsAny: + atype = resolve_native_size (atype); simd_opcode = MINT_SIMD_INTRINS_P_PP; if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_EQUALS_ANY; else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_EQUALS_ANY; @@ -621,6 +642,7 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature break; case SN_ShiftRightArithmetic: g_assert (scalar_arg == 1); + atype = resolve_native_size (atype); simd_opcode = MINT_SIMD_INTRINS_P_PP; if (atype == MONO_TYPE_I1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_RIGHT_SHIFT; else if (atype == MONO_TYPE_I2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_RIGHT_SHIFT; @@ -845,6 +867,8 @@ emit_sn_vector4 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *cs static gboolean packedsimd_type_matches (MonoTypeEnum type, int expected_type) { + type = resolve_native_size (type); + if (expected_type == PSIMD_ARGTYPE_ANY) return TRUE; else if (type == expected_type) @@ -1034,7 +1058,12 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature bool is_packedsimd = strcmp (m_class_get_name (cmethod->klass), "PackedSimd") == 0; if (is_packedsimd) { - vector_klass = mono_class_from_mono_type_internal (csignature->ret); + if (csignature->ret->type == MONO_TYPE_VOID && csignature->param_count > 1 && mono_type_is_pointer (csignature->params [0])) { + // The Store* methods have a more complicated signature + vector_klass = mono_class_from_mono_type_internal (csignature->params [1]); + } else { + vector_klass = mono_class_from_mono_type_internal (csignature->ret); + } } else { if (csignature->ret->type == MONO_TYPE_GENERICINST) { vector_klass = mono_class_from_mono_type_internal (csignature->ret);