diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 4d6abbf20effd8..265923a081ee62 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -60,8 +60,8 @@ So, set those parameters explicitly here. --> - <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' == 'true' and '$(RunAOTCompilation)' == 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MonoProjectRoot)\wasm\build\ILLink.Substitutions.WasmIntrinsics.xml" - <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' != 'true' or '$(RunAOTCompilation)' != 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MonoProjectRoot)\wasm\build\ILLink.Substitutions.NoWasmIntrinsics.xml" + <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' == 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MonoProjectRoot)\wasm\build\ILLink.Substitutions.WasmIntrinsics.xml" + <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' != 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MonoProjectRoot)\wasm\build\ILLink.Substitutions.NoWasmIntrinsics.xml" diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index d1c7d5ee8a726c..d6064b5dc04d8b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -2456,11 +2456,6 @@ internal static Vector128 ShuffleUnsafe(Vector128 vector, Vector128< return AdvSimd.Arm64.VectorTableLookup(vector, indices); } - if (PackedSimd.IsSupported) - { - return PackedSimd.Swizzle(vector, indices); - } - return Shuffle(vector, indices); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs index 680b8af89492bc..edf4be7115c92d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Numerics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; @@ -1872,28 +1874,45 @@ public abstract class PackedSimd // Conversions + private static Vector128 ConvertNarrowingSaturate(Vector128 lower, Vector128 upper) + where TResult : struct, INumber + where TIn : struct, INumber + { + var result = Vector128.Zero; + int c = Vector128.Count; + for (int i = 0; i < c; i++) + result = result.WithElement(i, TResult.CreateSaturating(lower[i])); + for (int i = 0; i < c; i++) + result = result.WithElement(i + c, TResult.CreateSaturating(upper[i])); + return result; + } + /// /// i8x16.narrow_i16x8_s /// [Intrinsic] - internal static Vector128 ConvertNarrowingSignedSaturate(Vector128 lower, Vector128 upper) => ConvertNarrowingSignedSaturate(lower, upper); + internal static Vector128 ConvertNarrowingSignedSaturate(Vector128 lower, Vector128 upper) => + ConvertNarrowingSaturate(lower, upper); /// /// i16x8.narrow_i32x4_s /// [Intrinsic] - internal static Vector128 ConvertNarrowingSignedSaturate(Vector128 lower, Vector128 upper) => ConvertNarrowingSignedSaturate(lower, upper); + internal static Vector128 ConvertNarrowingSignedSaturate(Vector128 lower, Vector128 upper) => + ConvertNarrowingSaturate(lower, upper); /// /// i8x16.narrow_i16x8_u /// [Intrinsic] - internal static Vector128 ConvertNarrowingUnsignedSaturate(Vector128 lower, Vector128 upper) => ConvertNarrowingUnsignedSaturate(lower, upper); + internal static Vector128 ConvertNarrowingUnsignedSaturate(Vector128 lower, Vector128 upper) => + ConvertNarrowingSaturate(lower, upper); /// /// i16x8.narrow_i32x4_u /// [Intrinsic] - internal static Vector128 ConvertNarrowingUnsignedSaturate(Vector128 lower, Vector128 upper) => ConvertNarrowingUnsignedSaturate(lower, upper); + internal static Vector128 ConvertNarrowingUnsignedSaturate(Vector128 lower, Vector128 upper) => + ConvertNarrowingSaturate(lower, upper); } } diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 2abac1ff7e0a5f..3bd329593837a0 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3849,6 +3849,10 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause memset (locals + ip [1], 0, ip [2]); ip += 3; MINT_IN_BREAK; + MINT_IN_CASE(MINT_NIY) + g_printf ("MONO interpreter: NIY encountered in method %s\n", frame->imethod->method->name); + g_assert_not_reached (); + MINT_IN_BREAK; MINT_IN_CASE(MINT_BREAK) ++ip; SAVE_INTERP_STATE (frame); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 4dd5886ee8d614..5f6c4a72f6dd6d 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -26,6 +26,7 @@ #define IROPDEF(opsymbol, opstring, oplength, num_dregs, num_sregs, optype) OPDEF(opsymbol, opstring, oplength, num_dregs, num_sregs, optype) #endif // IROPDEF +OPDEF(MINT_NIY, "niy", 1, 0, 0, MintOpNoArgs) OPDEF(MINT_BREAK, "break", 1, 0, 0, MintOpNoArgs) OPDEF(MINT_BREAKPOINT, "breakpoint", 1, 0, 0, MintOpNoArgs) @@ -844,7 +845,6 @@ OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOp #endif // HOST_BROWSER IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs) -IROPDEF(MINT_NIY, "niy", 1, 0, 0, MintOpNoArgs) IROPDEF(MINT_DEF, "def", 2, 1, 0, MintOpNoArgs) IROPDEF(MINT_IL_SEQ_POINT, "il_seq_point", 1, 0, 0, MintOpNoArgs) IROPDEF(MINT_DUMMY_USE, "dummy_use", 2, 0, 1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform-simd.c b/src/mono/mono/mini/interp/transform-simd.c index b259d3f994b1a1..04d388c3c6d43e 100644 --- a/src/mono/mono/mini/interp/transform-simd.c +++ b/src/mono/mono/mini/interp/transform-simd.c @@ -67,10 +67,6 @@ static guint16 sri_vector128_methods [] = { }; static guint16 sri_vector128_t_methods [] = { - SN_get_AllBitsSet, - SN_get_Count, - SN_get_One, - SN_get_Zero, SN_op_Addition, SN_op_BitwiseAnd, SN_op_BitwiseOr, @@ -84,12 +80,29 @@ static guint16 sri_vector128_t_methods [] = { SN_op_RightShift, SN_op_Subtraction, SN_op_UnaryNegation, - SN_op_UnsignedRightShift + SN_op_UnsignedRightShift, + SN_get_AllBitsSet, + SN_get_Count, + SN_get_One, + SN_get_Zero, }; static guint16 sri_packedsimd_methods [] = { + SN_Add, + SN_And, + SN_Bitmask, + SN_CompareEqual, + SN_CompareNotEqual, SN_ConvertNarrowingSignedSaturate, SN_ConvertNarrowingUnsignedSaturate, + SN_Dot, + SN_Multiply, + SN_Negate, + SN_ShiftLeft, + SN_ShiftRightArithmetic, + SN_ShiftRightLogical, + SN_Splat, + SN_Subtract, SN_Swizzle, SN_get_IsHardwareAccelerated, SN_get_IsSupported, @@ -534,22 +547,31 @@ static gboolean emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *csignature) { int id = lookup_intrins (sri_packedsimd_methods, sizeof (sri_packedsimd_methods), cmethod); - if (id == -1) - return FALSE; + // We don't early-out for an unrecognized method, we will generate an NIY later MonoClass *vector_klass = mono_class_from_mono_type_internal (csignature->ret); int vector_size = -1; if ((id == SN_get_IsSupported) || (id == SN_get_IsHardwareAccelerated)) { #if HOST_BROWSER - interp_add_ins (td, MINT_LDC_I4_1); + interp_add_ins (td, mono_opt_interp_simd_packedsimd ? MINT_LDC_I4_1 : MINT_LDC_I4_0); #else interp_add_ins (td, MINT_LDC_I4_0); #endif goto opcode_added; } + return FALSE; + #if HOST_BROWSER + if (!mono_opt_interp_simd_packedsimd || (id < 0)) { + g_print ("MONO interpreter: Disabled or unimplemented method: System.Runtime.Intrinsics.Wasm.PackedSimd.%s\n", cmethod->name); + // The packedsimd method implementations recurse infinitely and cause a stack overflow, + // so replace them with a NIY opcode instead that will assert + interp_add_ins (td, MINT_NIY); + goto opcode_added; + } + gint16 simd_opcode = -1; gint16 simd_intrins = -1; if (!m_class_is_simd_type (vector_klass)) @@ -644,6 +666,7 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature simd_intrins = map_packedsimd_intrins_based_on_atype (atype, INTERP_SIMD_INTRINSIC_WASM_I8X16_COMPARENOTEQUAL, TRUE); break; } + /* case SN_ConvertNarrowingSignedSaturate: { simd_opcode = MINT_SIMD_INTRINS_P_PP; if (atype == MONO_TYPE_I1) @@ -660,6 +683,7 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature simd_intrins = INTERP_SIMD_INTRINSIC_WASM_I16X8_NARROW_I32X4_U; break; } + */ default: return FALSE; } @@ -710,16 +734,9 @@ interp_emit_simd_intrinsics (TransformData *td, MonoMethod *cmethod, MonoMethodS return emit_sri_vector128 (td, cmethod, csignature); else if (!strcmp (class_name, "Vector128`1")) return emit_sri_vector128_t (td, cmethod, csignature); - } else if (mono_opt_interp_simd_packedsimd && !strcmp (class_ns, "System.Runtime.Intrinsics.Wasm")) { - if (!strcmp (class_name, "PackedSimd")) { - gboolean res = emit_sri_packedsimd (td, cmethod, csignature); -#if HOST_BROWSER - if (!res) - g_print ("MONO interpreter: Unsupported method: System.Runtime.Intrinsics.Wasm.PackedSimd.%s\n", cmethod->name); - g_assert (res); -#endif - return res; - } + } else if (!strcmp (class_ns, "System.Runtime.Intrinsics.Wasm")) { + if (!strcmp (class_name, "PackedSimd")) + return emit_sri_packedsimd (td, cmethod, csignature); } return FALSE; } diff --git a/src/mono/mono/utils/options-def.h b/src/mono/mono/utils/options-def.h index 6d8715c2465ffd..5b0272cd3cb8ac 100644 --- a/src/mono/mono/utils/options-def.h +++ b/src/mono/mono/utils/options-def.h @@ -60,12 +60,8 @@ DEFINE_BOOL_READONLY(readonly_flag, "readonly-flag", FALSE, "Example") DEFINE_BOOL(wasm_exceptions, "wasm-exceptions", FALSE, "Enable codegen for WASM exceptions") DEFINE_BOOL(wasm_gc_safepoints, "wasm-gc-safepoints", FALSE, "Use GC safepoints on WASM") DEFINE_BOOL(aot_lazy_assembly_load, "aot-lazy-assembly-load", FALSE, "Load assemblies referenced by AOT images lazily") -#if HOST_BROWSER DEFINE_BOOL(interp_simd_v128, "interp-simd-v128", FALSE, "Enable interpreter Vector128 support") -#else -DEFINE_BOOL(interp_simd_v128, "interp-simd-v128", TRUE, "Enable interpreter Vector128 support") -#endif -DEFINE_BOOL(interp_simd_packedsimd, "interp-simd-packedsimd", FALSE, "Enable interpreter WASM PackedSimd support") +DEFINE_BOOL(interp_simd_packedsimd, "interp-simd-packedsimd", TRUE, "Enable interpreter WASM PackedSimd support") #if HOST_BROWSER @@ -73,7 +69,7 @@ DEFINE_BOOL(interp_simd_packedsimd, "interp-simd-packedsimd", FALSE, "Enable int // and wasm modules between threads. before these can be enabled we need to implement all that #ifdef DISABLE_THREADS // traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces -DEFINE_BOOL(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", TRUE, "JIT interpreter opcode traces into WASM") +DEFINE_BOOL(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", FALSE, "JIT interpreter opcode traces into WASM") // interp_entry_enabled controls whether specialized interp_entry wrappers will be jitted DEFINE_BOOL(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled", TRUE, "JIT specialized WASM interp_entry wrappers") // jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 94bd9fe54f9d8c..57befe9bd87fe7 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -123,8 +123,8 @@ false false full - <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' == 'true' and '$(RunAOTCompilation)' == 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.WasmIntrinsics.xml" - <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' != 'true' or '$(RunAOTCompilation)' != 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.NoWasmIntrinsics.xml" + <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' == 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.WasmIntrinsics.xml" + <_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' != 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.NoWasmIntrinsics.xml" <_ExtraTrimmerArgs Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.LegacyJsInterop.xml" diff --git a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts index 5243e11d61dc65..d73696eb3dc1d0 100644 --- a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts @@ -3509,12 +3509,19 @@ const simdShiftTable = new Set([ SimdIntrinsic3.V128_I8_URIGHT_SHIFT, ]); -function append_stloc_simd_zero(builder: WasmBuilder, offset: number) { - builder.local("pLocals"); - builder.appendSimd(WasmSimdOpcode.v128_const); - builder.appendBytes(new Uint8Array(sizeOfV128)); - append_stloc_tail(builder, offset, WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_store); -} +const bitmaskTable : { [intrinsic: number]: WasmSimdOpcode } = { + [SimdIntrinsic2.V128_I1_EXTRACT_MSB]: WasmSimdOpcode.i8x16_bitmask, + [SimdIntrinsic2.V128_I2_EXTRACT_MSB]: WasmSimdOpcode.i16x8_bitmask, + [SimdIntrinsic2.V128_I4_EXTRACT_MSB]: WasmSimdOpcode.i32x4_bitmask, + [SimdIntrinsic2.V128_I8_EXTRACT_MSB]: WasmSimdOpcode.i64x2_bitmask, +}; + +const createScalarTable : { [intrinsic: number]: [WasmOpcode, WasmSimdOpcode] } = { + [SimdIntrinsic2.V128_I1_CREATE_SCALAR]: [WasmOpcode.i32_load8_s, WasmSimdOpcode.i8x16_replace_lane], + [SimdIntrinsic2.V128_I2_CREATE_SCALAR]: [WasmOpcode.i32_load16_s, WasmSimdOpcode.i16x8_replace_lane], + [SimdIntrinsic2.V128_I4_CREATE_SCALAR]: [WasmOpcode.i32_load, WasmSimdOpcode.i32x4_replace_lane], + [SimdIntrinsic2.V128_I8_CREATE_SCALAR]: [WasmOpcode.i64_load, WasmSimdOpcode.i64x2_replace_lane], +}; function emit_simd_2(builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic2): boolean { const simple = cwraps.mono_jiterp_get_simd_opcode(1, index); @@ -3525,35 +3532,33 @@ function emit_simd_2(builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrins 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: - // Zero then write scalar component - builder.local("pLocals"); - append_stloc_simd_zero(builder, getArgU16(ip, 1)); - append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load8_s); - append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store8); - return true; case SimdIntrinsic2.V128_I2_CREATE_SCALAR: - // Zero then write scalar component - builder.local("pLocals"); - append_stloc_simd_zero(builder, getArgU16(ip, 1)); - append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load16_s); - append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store16); - return true; case SimdIntrinsic2.V128_I4_CREATE_SCALAR: - // Zero then write scalar component - builder.local("pLocals"); - append_stloc_simd_zero(builder, getArgU16(ip, 1)); - append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); - append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store); - return true; - case SimdIntrinsic2.V128_I8_CREATE_SCALAR: - // Zero then write scalar component + case SimdIntrinsic2.V128_I8_CREATE_SCALAR: { + const tableEntry = createScalarTable[index]; builder.local("pLocals"); - append_stloc_simd_zero(builder, getArgU16(ip, 1)); - append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i64_load); - append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i64_store); + // Make a zero vector + builder.i52_const(0); + builder.appendSimd(WasmSimdOpcode.i64x2_splat); + // Load the scalar value + append_ldloc(builder, getArgU16(ip, 2), tableEntry[0]); + // Replace the first lane + builder.appendSimd(tableEntry[1]); + builder.appendU8(0); + // Store result + append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_store); return true; + } case SimdIntrinsic2.V128_I1_CREATE: append_simd_2_load(builder, ip, WasmSimdOpcode.v128_load8_splat);