diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs index c15ce4d164f6a2..6c74700ae76fcc 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs @@ -1,8 +1,7 @@ -using System.Diagnostics.CodeAnalysis; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. 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; @@ -84,19 +83,38 @@ public unsafe void FloatingPointOperationsTest() 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 }; + int[] values = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; fixed (int* ptr = values) { var loaded = PackedSimd.LoadVector128(ptr); + var loaded2 = PackedSimd.LoadVector128(ptr + 4); + Assert.Equal(Vector128.Create(1, 2, 3, 4), loaded); + Assert.Equal(Vector128.Create(5, 6, 7, 8), loaded2); + + var vl = Vector128.LoadUnsafe(ref values[0], (nuint)0); + var vl2 = Vector128.LoadUnsafe(ref values[0], (nuint)4); + Assert.Equal(loaded, vl); + Assert.Equal(loaded2, vl2); + + vl = Vector128.Load(ptr); + vl2 = Vector128.Load(ptr + 4); + Assert.Equal(loaded, vl); + Assert.Equal(loaded2, vl2); + + Assert.Equal(Vector128.Create(1, 2, 3, 4), loaded); + Assert.Equal(Vector128.Create(5, 6, 7, 8), loaded2); + - int[] storeTarget = new int[4]; + int[] storeTarget = new int[8]; fixed (int* storePtr = storeTarget) { PackedSimd.Store(storePtr, loaded); + PackedSimd.Store(storePtr + 4, loaded2); Assert.Equal(values, storeTarget); } } @@ -549,5 +567,49 @@ public void NativeUnsignedIntegerShiftTest() 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); } + + [Fact] + public unsafe void ConvertNarrowingSaturateSignedTest() + { + var v1 = Vector128.Create(32767, 32768, -32768, -32769); + var v2 = Vector128.Create(100, 200, -100, -200); + + var result = PackedSimd.ConvertNarrowingSaturateSigned(v1, v2); + + Assert.Equal(Vector128.Create((short)32767, (short)32767, (short)-32768, (short)-32768, (short)100, (short)200, (short)-100, (short)-200), result); + } + + [Fact] + public unsafe void ConvertNarrowingSaturateUnsignedTest() + { + var v1 = Vector128.Create(65535, 65536, -1, -100); + var v2 = Vector128.Create(100, 200, 300, 400); + + var result = PackedSimd.ConvertNarrowingSaturateUnsigned(v1, v2); + + Assert.Equal(Vector128.Create((ushort)65535, (ushort)65535, (ushort)0, (ushort)0, (ushort)100, (ushort)200, (ushort)300, (ushort)400), result); + } + + [Fact] + public unsafe void BitmaskTest() + { + var v1 = Vector128.Create((byte)0b00000001, (byte)0b00000010, (byte)0b00000100, (byte)0b00001000, + (byte)0b00010000, (byte)0b00100000, (byte)0b01000000, (byte)0b10000000, + (byte)0b00000001, (byte)0b00000010, (byte)0b00000100, (byte)0b00001000, + (byte)0b00010000, (byte)0b10100000, (byte)0b01000000, (byte)0b10000000); + + var v2 = Vector128.Create((ushort)0b1100001001100001, (ushort)0b0000000000000010, (ushort)0b0000000000000100, (ushort)0b0000000000001000, + (ushort)0b0000000000010000, (ushort)0b0000000000100000, (ushort)0b0000000001000000, (ushort)0b0000000010000000); + + var v3 = Vector128.Create(0b10000000000000000000000000000001, 0b00000000000111111000000000000010, + 0b00000000000000000000000000000100, 0b10000000000000000000000000001000); + + var bitmask1 = PackedSimd.Bitmask(v1); + var bitmask2 = PackedSimd.Bitmask(v2); + var bitmask3 = PackedSimd.Bitmask(v3); + Assert.Equal(0b1010000010000000, bitmask1); + Assert.Equal(0b1, bitmask2); + Assert.Equal(0b1001, bitmask3); + } } } \ No newline at end of file diff --git a/src/mono/browser/runtime/jiterpreter-tables.ts b/src/mono/browser/runtime/jiterpreter-tables.ts index 90b599a8bb553e..137cdb5df7b218 100644 --- a/src/mono/browser/runtime/jiterpreter-tables.ts +++ b/src/mono/browser/runtime/jiterpreter-tables.ts @@ -378,6 +378,21 @@ export const simdShiftTable = new Set([ SimdIntrinsic3.V128_I2_URIGHT_SHIFT, SimdIntrinsic3.V128_I4_URIGHT_SHIFT, SimdIntrinsic3.V128_I8_URIGHT_SHIFT, + + SimdIntrinsic3.ShiftLeftD1, + SimdIntrinsic3.ShiftLeftD2, + SimdIntrinsic3.ShiftLeftD4, + SimdIntrinsic3.ShiftLeftD8, + + SimdIntrinsic3.ShiftRightArithmeticD1, + SimdIntrinsic3.ShiftRightArithmeticD2, + SimdIntrinsic3.ShiftRightArithmeticD4, + SimdIntrinsic3.ShiftRightArithmeticD8, + + SimdIntrinsic3.ShiftRightLogicalD1, + SimdIntrinsic3.ShiftRightLogicalD2, + SimdIntrinsic3.ShiftRightLogicalD4, + SimdIntrinsic3.ShiftRightLogicalD8, ]); export const simdExtractTable: { [intrinsic: number]: [laneCount: number, laneStoreOpcode: WasmOpcode] } = { @@ -428,6 +443,11 @@ export const bitmaskTable: { [intrinsic: number]: WasmSimdOpcode } = { [SimdIntrinsic2.V128_I2_EXTRACT_MSB]: WasmSimdOpcode.i16x8_bitmask, [SimdIntrinsic2.V128_I4_EXTRACT_MSB]: WasmSimdOpcode.i32x4_bitmask, [SimdIntrinsic2.V128_I8_EXTRACT_MSB]: WasmSimdOpcode.i64x2_bitmask, + + [SimdIntrinsic2.BitmaskD1]: WasmSimdOpcode.i8x16_bitmask, + [SimdIntrinsic2.BitmaskD2]: WasmSimdOpcode.i16x8_bitmask, + [SimdIntrinsic2.BitmaskD4]: WasmSimdOpcode.i32x4_bitmask, + [SimdIntrinsic2.BitmaskD8]: WasmSimdOpcode.i64x2_bitmask, }; export const createScalarTable: { [intrinsic: number]: [WasmOpcode, WasmSimdOpcode] } = { diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index 56d1329de5251f..8da5b65fad7044 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -3688,6 +3688,15 @@ function append_simd_4_load (builder: WasmBuilder, ip: MintOpcodePtr) { function emit_simd_2 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic2): boolean { const simple = cwraps.mono_jiterp_get_simd_opcode(1, index); + const bitmask = bitmaskTable[index]; + + if (bitmask) { + append_simd_2_load(builder, ip); + builder.appendSimd(bitmask); + append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store); + return true; + } + if (simple >= 0) { if (simdLoadTable.has(index)) { // Indirect load, so v1 is T** and res is Vector128* @@ -3704,14 +3713,6 @@ function emit_simd_2 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrin return true; } - const bitmask = bitmaskTable[index]; - if (bitmask) { - append_simd_2_load(builder, ip); - builder.appendSimd(bitmask); - append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store); - return true; - } - switch (index) { case SimdIntrinsic2.V128_I1_CREATE_SCALAR: case SimdIntrinsic2.V128_I2_CREATE_SCALAR: diff --git a/src/mono/mono/mini/interp/transform-simd.c b/src/mono/mono/mini/interp/transform-simd.c index 318207bd0fc138..ae003f4a997eeb 100644 --- a/src/mono/mono/mini/interp/transform-simd.c +++ b/src/mono/mono/mini/interp/transform-simd.c @@ -156,6 +156,7 @@ static guint16 packedsimd_alias_methods [] = { SN_ConvertToSingle, SN_Divide, SN_Equals, + SN_ExtractMostSignificantBits, SN_Floor, SN_GreaterThan, SN_GreaterThanOrEqual, @@ -179,7 +180,6 @@ static guint16 packedsimd_alias_methods [] = { SN_WidenUpper, SN_Xor, // operators -#if 0 SN_op_Addition, SN_op_BitwiseAnd, SN_op_BitwiseOr, @@ -192,7 +192,6 @@ static guint16 packedsimd_alias_methods [] = { SN_op_Subtraction, SN_op_UnaryNegation, SN_op_UnsignedRightShift, -#endif }; static MonoTypeEnum @@ -365,6 +364,7 @@ emit_common_simd_operations (TransformData *td, int id, int atype, int vector_si else if (atype == MONO_TYPE_U1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_URIGHT_SHIFT; else if (atype == MONO_TYPE_U2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_URIGHT_SHIFT; else if (atype == MONO_TYPE_U4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_URIGHT_SHIFT; + else if (atype == MONO_TYPE_U8) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_URIGHT_SHIFT; break; case SN_op_Subtraction: *simd_opcode = MINT_SIMD_INTRINS_P_PP; @@ -691,6 +691,7 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature else if (atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_URIGHT_SHIFT; else if (atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_URIGHT_SHIFT; else if (atype == MONO_TYPE_U4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_URIGHT_SHIFT; + else if (atype == MONO_TYPE_U8) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_URIGHT_SHIFT; break; case SN_Shuffle: simd_opcode = MINT_SIMD_INTRINS_P_PP; @@ -1163,6 +1164,9 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature case SN_Equals: cmethod_name = "CompareEqual"; break; + case SN_ExtractMostSignificantBits: + cmethod_name = "Bitmask"; + break; case SN_BitwiseAnd: case SN_op_BitwiseAnd: cmethod_name = "And"; @@ -1177,6 +1181,8 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature break; case SN_Load: case SN_LoadUnsafe: + if (csignature->param_count != 1) + return FALSE; cmethod_name = "LoadVector128"; break; case SN_Round: @@ -1229,6 +1235,7 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature break; case SN_ConvertToInt32: cmethod_name = "ConvertToInt32Saturate"; + break; case SN_ShiftLeft: case SN_ShiftRightLogical: case SN_ShiftRightArithmetic: