Skip to content

Commit 7c75cbf

Browse files
authored
[wasm] Add Vector128 and PackedSimd support to the jiterpreter; add PackedSimd to the interpreter (#82773)
* Add PackedSIMD support to the interpreter (off by default) * Add SIMD support to the jiterpreter * Add runtime options governing interpreter vector128 and packedsimd support * Add some R4 vector128 operations to the interpreter * Fix jiterpreter MINT_POPCNT_I8 implementation * Enable compiling the runtime with wasm simd support so that intrinsics can be used * Add browser-bench measurements for packing vector128
1 parent d7c94a8 commit 7c75cbf

23 files changed

+1533
-196
lines changed

src/mono/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ elseif(CLR_CMAKE_HOST_OS STREQUAL "emscripten")
270270
add_compile_options(-Wno-strict-prototypes)
271271
add_compile_options(-Wno-unused-but-set-variable)
272272
add_compile_options(-Wno-single-bit-bitfield-constant-conversion)
273+
add_compile_options(-msimd128)
273274
set(DISABLE_EXECUTABLES 1)
274275
# FIXME: Is there a cmake option for this ?
275276
set(DISABLE_SHARED_LIBS 1)

src/mono/mono/mini/interp/interp-internals.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ typedef enum {
102102

103103
#define PROFILE_INTERP 0
104104

105-
#if !HOST_BROWSER && __GNUC__
105+
#if __GNUC__
106106
#define INTERP_ENABLE_SIMD
107107
#endif
108108

@@ -342,6 +342,12 @@ mono_jiterp_stackval_from_data (MonoType *type, stackval *result, const void *da
342342
gpointer
343343
mono_jiterp_frame_data_allocator_alloc (FrameDataAllocator *stack, InterpFrame *frame, int size);
344344

345+
gpointer
346+
mono_jiterp_get_simd_intrinsic (int arity, int index);
347+
348+
int
349+
mono_jiterp_get_simd_opcode (int arity, int index);
350+
345351
#endif
346352

347353
static inline int

src/mono/mono/mini/interp/interp-simd-intrins.def

Lines changed: 185 additions & 81 deletions
Large diffs are not rendered by default.

src/mono/mono/mini/interp/interp-simd.c

Lines changed: 128 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#include "interp-internals.h"
33
#include "interp-simd.h"
44

5+
#if HOST_BROWSER
6+
#include <wasm_simd128.h>
7+
#endif
8+
59
#ifdef INTERP_ENABLE_SIMD
610

711
typedef gint64 v128_i8 __attribute__ ((vector_size (SIZEOF_V128)));
@@ -12,6 +16,7 @@ typedef gint16 v128_i2 __attribute__ ((vector_size (SIZEOF_V128)));
1216
typedef guint16 v128_u2 __attribute__ ((vector_size (SIZEOF_V128)));
1317
typedef gint8 v128_i1 __attribute__ ((vector_size (SIZEOF_V128)));
1418
typedef guint8 v128_u1 __attribute__ ((vector_size (SIZEOF_V128)));
19+
typedef float v128_r4 __attribute__ ((vector_size (SIZEOF_V128)));
1520

1621
// get_AllBitsSet
1722
static void
@@ -39,6 +44,12 @@ interp_v128_i4_op_addition (gpointer res, gpointer v1, gpointer v2)
3944
*(v128_i4*)res = *(v128_i4*)v1 + *(v128_i4*)v2;
4045
}
4146

47+
static void
48+
interp_v128_r4_op_addition (gpointer res, gpointer v1, gpointer v2)
49+
{
50+
*(v128_r4*)res = *(v128_r4*)v1 + *(v128_r4*)v2;
51+
}
52+
4253
// op_Subtraction
4354
static void
4455
interp_v128_i1_op_subtraction (gpointer res, gpointer v1, gpointer v2)
@@ -58,6 +69,12 @@ interp_v128_i4_op_subtraction (gpointer res, gpointer v1, gpointer v2)
5869
*(v128_i4*)res = *(v128_i4*)v1 - *(v128_i4*)v2;
5970
}
6071

72+
static void
73+
interp_v128_r4_op_subtraction (gpointer res, gpointer v1, gpointer v2)
74+
{
75+
*(v128_r4*)res = *(v128_r4*)v1 - *(v128_r4*)v2;
76+
}
77+
6178
// op_BitwiseAnd
6279
static void
6380
interp_v128_op_bitwise_and (gpointer res, gpointer v1, gpointer v2)
@@ -124,6 +141,18 @@ interp_v128_i4_op_multiply (gpointer res, gpointer v1, gpointer v2)
124141
*(v128_i4*)res = *(v128_i4*)v1 * *(v128_i4*)v2;
125142
}
126143

144+
static void
145+
interp_v128_r4_op_multiply (gpointer res, gpointer v1, gpointer v2)
146+
{
147+
*(v128_r4*)res = *(v128_r4*)v1 * *(v128_r4*)v2;
148+
}
149+
150+
static void
151+
interp_v128_r4_op_division (gpointer res, gpointer v1, gpointer v2)
152+
{
153+
*(v128_r4*)res = *(v128_r4*)v1 / *(v128_r4*)v2;
154+
}
155+
127156
// op_UnaryNegation
128157
static void
129158
interp_v128_i1_op_negation (gpointer res, gpointer v1)
@@ -535,32 +564,122 @@ interp_v128_i8_shuffle (gpointer res, gpointer v1, gpointer v2)
535564
V128_SHUFFLE (gint64, guint64);
536565
}
537566

538-
#define INTERP_SIMD_INTRINSIC_P_P(a,b)
539-
#define INTERP_SIMD_INTRINSIC_P_PP(a,b)
540-
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b)
567+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c)
568+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c)
569+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c)
570+
571+
// For the wasm packed simd intrinsics we want to automatically generate the C implementations from
572+
// their corresponding clang intrinsics. See also:
573+
// https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/wasm_simd128.h
574+
// In this context V means Vector128 and P means void* pointer.
575+
#ifdef HOST_BROWSER
576+
577+
static v128_t
578+
_interp_wasm_simd_assert_not_reached (v128_t lhs, v128_t rhs) {
579+
g_assert_not_reached ();
580+
}
581+
582+
#define INTERP_WASM_SIMD_INTRINSIC_V_P(id, c_intrinsic, wasm_opcode) \
583+
static void \
584+
_mono_interp_simd_ ## id (gpointer res, gpointer v1) { \
585+
*((v128_t *)res) = c_intrinsic (v1); \
586+
}
587+
588+
#define INTERP_WASM_SIMD_INTRINSIC_V_V(id, c_intrinsic, wasm_opcode) \
589+
static void \
590+
_mono_interp_simd_ ## id (gpointer res, gpointer v1) { \
591+
*((v128_t *)res) = c_intrinsic (*((v128_t *)v1)); \
592+
}
593+
594+
#define INTERP_WASM_SIMD_INTRINSIC_I_V(id, c_intrinsic, wasm_opcode) \
595+
static void \
596+
_mono_interp_simd_ ## id (gpointer res, gpointer v1) { \
597+
*((int32_t *)res) = c_intrinsic (*((v128_t *)v1)); \
598+
}
599+
600+
#define INTERP_WASM_SIMD_INTRINSIC_V_VV(id, c_intrinsic, wasm_opcode) \
601+
static void \
602+
_mono_interp_simd_ ## id (gpointer res, gpointer v1, gpointer v2) { \
603+
*((v128_t *)res) = c_intrinsic (*((v128_t *)v1), *((v128_t *)v2)); \
604+
}
605+
606+
#define INTERP_WASM_SIMD_INTRINSIC_V_VI(id, c_intrinsic, wasm_opcode) \
607+
static void \
608+
_mono_interp_simd_ ## id (gpointer res, gpointer v1, gpointer v2) { \
609+
*((v128_t *)res) = c_intrinsic (*((v128_t *)v1), *((int *)v2)); \
610+
}
611+
612+
#define INTERP_WASM_SIMD_INTRINSIC_V_VVV(id, c_intrinsic, wasm_opcode) \
613+
static void \
614+
_mono_interp_simd_ ## id (gpointer res, gpointer v1, gpointer v2, gpointer v3) { \
615+
*((v128_t *)res) = c_intrinsic (*((v128_t *)v1), *((v128_t *)v2), *((v128_t *)v3)); \
616+
}
617+
618+
#include "interp-simd-intrins.def"
619+
620+
#undef INTERP_WASM_SIMD_INTRINSIC_V_P
621+
#undef INTERP_WASM_SIMD_INTRINSIC_V_V
622+
#undef INTERP_WASM_SIMD_INTRINSIC_I_V
623+
#undef INTERP_WASM_SIMD_INTRINSIC_V_VV
624+
#undef INTERP_WASM_SIMD_INTRINSIC_V_VI
625+
#undef INTERP_WASM_SIMD_INTRINSIC_V_VVV
626+
627+
// Now generate the wasm opcode tables for the intrinsics
628+
629+
#undef INTERP_SIMD_INTRINSIC_P_P
630+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c) c,
631+
632+
int interp_simd_p_p_wasm_opcode_table [] = {
633+
#include "interp-simd-intrins.def"
634+
};
635+
636+
#undef INTERP_SIMD_INTRINSIC_P_P
637+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c)
638+
639+
#undef INTERP_SIMD_INTRINSIC_P_PP
640+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c) c,
641+
642+
int interp_simd_p_pp_wasm_opcode_table [] = {
643+
#include "interp-simd-intrins.def"
644+
};
645+
646+
#undef INTERP_SIMD_INTRINSIC_P_PP
647+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c)
648+
649+
#undef INTERP_SIMD_INTRINSIC_P_PPP
650+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c) c,
651+
652+
int interp_simd_p_ppp_wasm_opcode_table [] = {
653+
#include "interp-simd-intrins.def"
654+
};
655+
656+
#undef INTERP_SIMD_INTRINSIC_P_PPP
657+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c)
658+
659+
#endif // HOST_BROWSER
541660

542661
#undef INTERP_SIMD_INTRINSIC_P_P
543-
#define INTERP_SIMD_INTRINSIC_P_P(a,b) b,
662+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c) b,
544663
PP_SIMD_Method interp_simd_p_p_table [] = {
545664
#include "interp-simd-intrins.def"
546665
};
547666
#undef INTERP_SIMD_INTRINSIC_P_P
548-
#define INTERP_SIMD_INTRINSIC_P_P(a,b)
667+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c)
549668

550669
#undef INTERP_SIMD_INTRINSIC_P_PP
551-
#define INTERP_SIMD_INTRINSIC_P_PP(a,b) b,
670+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c) b,
552671
PPP_SIMD_Method interp_simd_p_pp_table [] = {
553672
#include "interp-simd-intrins.def"
554673
};
555674
#undef INTERP_SIMD_INTRINSIC_P_PP
556-
#define INTERP_SIMD_INTRINSIC_P_PP(a,b)
675+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c)
557676

558677
#undef INTERP_SIMD_INTRINSIC_P_PPP
559-
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b) b,
678+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c) b,
560679
PPPP_SIMD_Method interp_simd_p_ppp_table [] = {
561680
#include "interp-simd-intrins.def"
562681
};
563682
#undef INTERP_SIMD_INTRINSIC_P_PPP
564-
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b)
683+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c)
565684

566685
#endif // INTERP_ENABLE_SIMD

src/mono/mono/mini/interp/interp-simd.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ extern PP_SIMD_Method interp_simd_p_p_table [];
1111
extern PPP_SIMD_Method interp_simd_p_pp_table [];
1212
extern PPPP_SIMD_Method interp_simd_p_ppp_table [];
1313

14+
#if HOST_BROWSER
15+
extern int interp_simd_p_p_wasm_opcode_table [];
16+
extern int interp_simd_p_pp_wasm_opcode_table [];
17+
extern int interp_simd_p_ppp_wasm_opcode_table [];
18+
#endif
19+
1420
#endif /* __MONO_MINI_INTERP_SIMD_H__ */
1521

1622

src/mono/mono/mini/interp/interp.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8907,4 +8907,42 @@ mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackva
89078907
*dest = mono_interp_enum_hasflag (sp1, sp2, klass);
89088908
}
89098909

8910+
EMSCRIPTEN_KEEPALIVE gpointer
8911+
mono_jiterp_get_simd_intrinsic (int arity, int index)
8912+
{
8913+
#ifdef INTERP_ENABLE_SIMD
8914+
switch (arity) {
8915+
case 1:
8916+
return interp_simd_p_p_table [index];
8917+
case 2:
8918+
return interp_simd_p_pp_table [index];
8919+
case 3:
8920+
return interp_simd_p_ppp_table [index];
8921+
default:
8922+
g_assert_not_reached();
8923+
}
8924+
#else
8925+
g_assert_not_reached();
8926+
#endif
8927+
}
8928+
8929+
EMSCRIPTEN_KEEPALIVE int
8930+
mono_jiterp_get_simd_opcode (int arity, int index)
8931+
{
8932+
#ifdef INTERP_ENABLE_SIMD
8933+
switch (arity) {
8934+
case 1:
8935+
return interp_simd_p_p_wasm_opcode_table [index];
8936+
case 2:
8937+
return interp_simd_p_pp_wasm_opcode_table [index];
8938+
case 3:
8939+
return interp_simd_p_ppp_wasm_opcode_table [index];
8940+
default:
8941+
g_assert_not_reached();
8942+
}
8943+
#else
8944+
g_assert_not_reached();
8945+
#endif
8946+
}
8947+
89108948
#endif

src/mono/mono/mini/interp/mintops.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,35 +41,35 @@ typedef enum {
4141

4242
/* SIMD opcodes, grouped by signature */
4343

44-
#define INTERP_SIMD_INTRINSIC_P_P(a,b)
45-
#define INTERP_SIMD_INTRINSIC_P_PP(a,b)
46-
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b)
44+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c)
45+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c)
46+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c)
4747

4848
#undef INTERP_SIMD_INTRINSIC_P_P
49-
#define INTERP_SIMD_INTRINSIC_P_P(a,b) a,
49+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c) a,
5050
typedef enum {
5151
#include "interp-simd-intrins.def"
5252
} MintSIMDOpsPP;
5353
#undef INTERP_SIMD_INTRINSIC_P_P
54-
#define INTERP_SIMD_INTRINSIC_P_P(a,b)
54+
#define INTERP_SIMD_INTRINSIC_P_P(a,b,c)
5555

5656
#undef INTERP_SIMD_INTRINSIC_P_PP
57-
#define INTERP_SIMD_INTRINSIC_P_PP(a,b) a,
57+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c) a,
5858
typedef enum {
5959
#include "interp-simd-intrins.def"
6060
INTERP_SIMD_INTRINSIC_P_PP_LAST
6161
} MintSIMDOpsPPP;
6262
#undef INTERP_SIMD_INTRINSIC_P_PP
63-
#define INTERP_SIMD_INTRINSIC_P_PP(a,b)
63+
#define INTERP_SIMD_INTRINSIC_P_PP(a,b,c)
6464

6565
#undef INTERP_SIMD_INTRINSIC_P_PPP
66-
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b) a,
66+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c) a,
6767
typedef enum {
6868
#include "interp-simd-intrins.def"
6969
INTERP_SIMD_INTRINSIC_P_PPP_LAST
7070
} MintSIMDOpsPPPP;
7171
#undef INTERP_SIMD_INTRINSIC_P_PPP
72-
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b)
72+
#define INTERP_SIMD_INTRINSIC_P_PPP(a,b,c)
7373

7474
#if NO_UNALIGNED_ACCESS
7575
# if G_BYTE_ORDER == G_LITTLE_ENDIAN

src/mono/mono/mini/interp/simd-methods.def

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
SIMD_METHOD(get_Count)
22
SIMD_METHOD(get_AllBitsSet)
33
SIMD_METHOD(get_IsHardwareAccelerated)
4+
SIMD_METHOD(get_IsSupported)
45
SIMD_METHOD(get_Item)
56
SIMD_METHOD(get_One)
67
SIMD_METHOD(get_Zero)
78
SIMD_METHOD(op_Addition)
89
SIMD_METHOD(op_BitwiseAnd)
910
SIMD_METHOD(op_BitwiseOr)
11+
SIMD_METHOD(op_Division)
1012
SIMD_METHOD(op_Equality)
1113
SIMD_METHOD(op_ExclusiveOr)
1214
SIMD_METHOD(op_Explicit)
@@ -24,6 +26,7 @@ SIMD_METHOD(ConditionalSelect)
2426
SIMD_METHOD(Create)
2527
SIMD_METHOD(CreateScalar)
2628
SIMD_METHOD(CreateScalarUnsafe)
29+
2730
SIMD_METHOD(Equals)
2831
SIMD_METHOD(ExtractMostSignificantBits)
2932
SIMD_METHOD(GreaterThan)
@@ -36,3 +39,20 @@ SIMD_METHOD(ShiftRightLogical)
3639
SIMD_METHOD(Shuffle)
3740
SIMD_METHOD(WidenLower)
3841
SIMD_METHOD(WidenUpper)
42+
43+
// PackedSimd
44+
SIMD_METHOD(Splat)
45+
SIMD_METHOD(ExtractLane)
46+
SIMD_METHOD(ReplaceLane)
47+
SIMD_METHOD(Swizzle)
48+
SIMD_METHOD(Add)
49+
SIMD_METHOD(Subtract)
50+
SIMD_METHOD(Multiply)
51+
SIMD_METHOD(Dot)
52+
SIMD_METHOD(Negate)
53+
SIMD_METHOD(And)
54+
SIMD_METHOD(Bitmask)
55+
SIMD_METHOD(CompareEqual)
56+
SIMD_METHOD(CompareNotEqual)
57+
SIMD_METHOD(ConvertNarrowingSignedSaturate)
58+
SIMD_METHOD(ConvertNarrowingUnsignedSaturate)

0 commit comments

Comments
 (0)