Skip to content

Commit 91d74fc

Browse files
authored
[wasm][interp] Jiterp packedsimd shifts (#114669)
* Teach the jiterpreter about the PackedSimd opcodes directly * Teach jiterp about Bitmask directly and add alias * Fix the overmatching on Load* * Add more tests * Add some PackedSimd.Bitmask tests * fix missed edit * Add another missing URIGHT match
1 parent f79c098 commit 91d74fc

File tree

4 files changed

+106
-16
lines changed

4 files changed

+106
-16
lines changed

src/libraries/System.Runtime.Intrinsics/tests/Wasm/PackedSimdTests.cs

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
using System.Diagnostics.CodeAnalysis;
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
24
using System.Numerics;
3-
using System.Reflection;
4-
using System.Runtime.CompilerServices;
5-
using System.Runtime.InteropServices;
65
using System.Runtime.Intrinsics;
76
using System.Runtime.Intrinsics.Wasm;
87
using System.Tests;
@@ -84,19 +83,38 @@ public unsafe void FloatingPointOperationsTest()
8483
Assert.Equal(Vector128.Create(4.0f, 9.0f, 16.0f, 25.0f), floorResult);
8584
}
8685

86+
8787
[Fact]
8888
public unsafe void LoadStoreTest()
8989
{
90-
int[] values = new int[] { 1, 2, 3, 4 };
90+
int[] values = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
9191
fixed (int* ptr = values)
9292
{
9393
var loaded = PackedSimd.LoadVector128(ptr);
94+
var loaded2 = PackedSimd.LoadVector128(ptr + 4);
95+
9496
Assert.Equal(Vector128.Create(1, 2, 3, 4), loaded);
97+
Assert.Equal(Vector128.Create(5, 6, 7, 8), loaded2);
98+
99+
var vl = Vector128.LoadUnsafe(ref values[0], (nuint)0);
100+
var vl2 = Vector128.LoadUnsafe(ref values[0], (nuint)4);
101+
Assert.Equal(loaded, vl);
102+
Assert.Equal(loaded2, vl2);
103+
104+
vl = Vector128.Load(ptr);
105+
vl2 = Vector128.Load(ptr + 4);
106+
Assert.Equal(loaded, vl);
107+
Assert.Equal(loaded2, vl2);
108+
109+
Assert.Equal(Vector128.Create(1, 2, 3, 4), loaded);
110+
Assert.Equal(Vector128.Create(5, 6, 7, 8), loaded2);
111+
95112

96-
int[] storeTarget = new int[4];
113+
int[] storeTarget = new int[8];
97114
fixed (int* storePtr = storeTarget)
98115
{
99116
PackedSimd.Store(storePtr, loaded);
117+
PackedSimd.Store(storePtr + 4, loaded2);
100118
Assert.Equal(values, storeTarget);
101119
}
102120
}
@@ -549,5 +567,49 @@ public void NativeUnsignedIntegerShiftTest()
549567
Assert.Equal(Vector128.Create([(nuint)64, unchecked((nuint)(-64)), (nuint)128, unchecked((nuint)(-128))]), leftShift);
550568
Assert.Equal(Vector128.Create([(nuint)4, (nuint)1073741820, (nuint)8, (nuint)1073741816]), rightShiftLogical);
551569
}
570+
571+
[Fact]
572+
public unsafe void ConvertNarrowingSaturateSignedTest()
573+
{
574+
var v1 = Vector128.Create(32767, 32768, -32768, -32769);
575+
var v2 = Vector128.Create(100, 200, -100, -200);
576+
577+
var result = PackedSimd.ConvertNarrowingSaturateSigned(v1, v2);
578+
579+
Assert.Equal(Vector128.Create((short)32767, (short)32767, (short)-32768, (short)-32768, (short)100, (short)200, (short)-100, (short)-200), result);
580+
}
581+
582+
[Fact]
583+
public unsafe void ConvertNarrowingSaturateUnsignedTest()
584+
{
585+
var v1 = Vector128.Create(65535, 65536, -1, -100);
586+
var v2 = Vector128.Create(100, 200, 300, 400);
587+
588+
var result = PackedSimd.ConvertNarrowingSaturateUnsigned(v1, v2);
589+
590+
Assert.Equal(Vector128.Create((ushort)65535, (ushort)65535, (ushort)0, (ushort)0, (ushort)100, (ushort)200, (ushort)300, (ushort)400), result);
591+
}
592+
593+
[Fact]
594+
public unsafe void BitmaskTest()
595+
{
596+
var v1 = Vector128.Create((byte)0b00000001, (byte)0b00000010, (byte)0b00000100, (byte)0b00001000,
597+
(byte)0b00010000, (byte)0b00100000, (byte)0b01000000, (byte)0b10000000,
598+
(byte)0b00000001, (byte)0b00000010, (byte)0b00000100, (byte)0b00001000,
599+
(byte)0b00010000, (byte)0b10100000, (byte)0b01000000, (byte)0b10000000);
600+
601+
var v2 = Vector128.Create((ushort)0b1100001001100001, (ushort)0b0000000000000010, (ushort)0b0000000000000100, (ushort)0b0000000000001000,
602+
(ushort)0b0000000000010000, (ushort)0b0000000000100000, (ushort)0b0000000001000000, (ushort)0b0000000010000000);
603+
604+
var v3 = Vector128.Create(0b10000000000000000000000000000001, 0b00000000000111111000000000000010,
605+
0b00000000000000000000000000000100, 0b10000000000000000000000000001000);
606+
607+
var bitmask1 = PackedSimd.Bitmask(v1);
608+
var bitmask2 = PackedSimd.Bitmask(v2);
609+
var bitmask3 = PackedSimd.Bitmask(v3);
610+
Assert.Equal(0b1010000010000000, bitmask1);
611+
Assert.Equal(0b1, bitmask2);
612+
Assert.Equal(0b1001, bitmask3);
613+
}
552614
}
553615
}

src/mono/browser/runtime/jiterpreter-tables.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,21 @@ export const simdShiftTable = new Set<SimdIntrinsic3>([
378378
SimdIntrinsic3.V128_I2_URIGHT_SHIFT,
379379
SimdIntrinsic3.V128_I4_URIGHT_SHIFT,
380380
SimdIntrinsic3.V128_I8_URIGHT_SHIFT,
381+
382+
SimdIntrinsic3.ShiftLeftD1,
383+
SimdIntrinsic3.ShiftLeftD2,
384+
SimdIntrinsic3.ShiftLeftD4,
385+
SimdIntrinsic3.ShiftLeftD8,
386+
387+
SimdIntrinsic3.ShiftRightArithmeticD1,
388+
SimdIntrinsic3.ShiftRightArithmeticD2,
389+
SimdIntrinsic3.ShiftRightArithmeticD4,
390+
SimdIntrinsic3.ShiftRightArithmeticD8,
391+
392+
SimdIntrinsic3.ShiftRightLogicalD1,
393+
SimdIntrinsic3.ShiftRightLogicalD2,
394+
SimdIntrinsic3.ShiftRightLogicalD4,
395+
SimdIntrinsic3.ShiftRightLogicalD8,
381396
]);
382397

383398
export const simdExtractTable: { [intrinsic: number]: [laneCount: number, laneStoreOpcode: WasmOpcode] } = {
@@ -428,6 +443,11 @@ export const bitmaskTable: { [intrinsic: number]: WasmSimdOpcode } = {
428443
[SimdIntrinsic2.V128_I2_EXTRACT_MSB]: WasmSimdOpcode.i16x8_bitmask,
429444
[SimdIntrinsic2.V128_I4_EXTRACT_MSB]: WasmSimdOpcode.i32x4_bitmask,
430445
[SimdIntrinsic2.V128_I8_EXTRACT_MSB]: WasmSimdOpcode.i64x2_bitmask,
446+
447+
[SimdIntrinsic2.BitmaskD1]: WasmSimdOpcode.i8x16_bitmask,
448+
[SimdIntrinsic2.BitmaskD2]: WasmSimdOpcode.i16x8_bitmask,
449+
[SimdIntrinsic2.BitmaskD4]: WasmSimdOpcode.i32x4_bitmask,
450+
[SimdIntrinsic2.BitmaskD8]: WasmSimdOpcode.i64x2_bitmask,
431451
};
432452

433453
export const createScalarTable: { [intrinsic: number]: [WasmOpcode, WasmSimdOpcode] } = {

src/mono/browser/runtime/jiterpreter-trace-generator.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3688,6 +3688,15 @@ function append_simd_4_load (builder: WasmBuilder, ip: MintOpcodePtr) {
36883688

36893689
function emit_simd_2 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic2): boolean {
36903690
const simple = <WasmSimdOpcode>cwraps.mono_jiterp_get_simd_opcode(1, index);
3691+
const bitmask = bitmaskTable[index];
3692+
3693+
if (bitmask) {
3694+
append_simd_2_load(builder, ip);
3695+
builder.appendSimd(bitmask);
3696+
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
3697+
return true;
3698+
}
3699+
36913700
if (simple >= 0) {
36923701
if (simdLoadTable.has(index)) {
36933702
// Indirect load, so v1 is T** and res is Vector128*
@@ -3704,14 +3713,6 @@ function emit_simd_2 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrin
37043713
return true;
37053714
}
37063715

3707-
const bitmask = bitmaskTable[index];
3708-
if (bitmask) {
3709-
append_simd_2_load(builder, ip);
3710-
builder.appendSimd(bitmask);
3711-
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
3712-
return true;
3713-
}
3714-
37153716
switch (index) {
37163717
case SimdIntrinsic2.V128_I1_CREATE_SCALAR:
37173718
case SimdIntrinsic2.V128_I2_CREATE_SCALAR:

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ static guint16 packedsimd_alias_methods [] = {
156156
SN_ConvertToSingle,
157157
SN_Divide,
158158
SN_Equals,
159+
SN_ExtractMostSignificantBits,
159160
SN_Floor,
160161
SN_GreaterThan,
161162
SN_GreaterThanOrEqual,
@@ -179,7 +180,6 @@ static guint16 packedsimd_alias_methods [] = {
179180
SN_WidenUpper,
180181
SN_Xor,
181182
// operators
182-
#if 0
183183
SN_op_Addition,
184184
SN_op_BitwiseAnd,
185185
SN_op_BitwiseOr,
@@ -192,7 +192,6 @@ static guint16 packedsimd_alias_methods [] = {
192192
SN_op_Subtraction,
193193
SN_op_UnaryNegation,
194194
SN_op_UnsignedRightShift,
195-
#endif
196195
};
197196

198197
static MonoTypeEnum
@@ -365,6 +364,7 @@ emit_common_simd_operations (TransformData *td, int id, int atype, int vector_si
365364
else if (atype == MONO_TYPE_U1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_URIGHT_SHIFT;
366365
else if (atype == MONO_TYPE_U2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_URIGHT_SHIFT;
367366
else if (atype == MONO_TYPE_U4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_URIGHT_SHIFT;
367+
else if (atype == MONO_TYPE_U8) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_URIGHT_SHIFT;
368368
break;
369369
case SN_op_Subtraction:
370370
*simd_opcode = MINT_SIMD_INTRINS_P_PP;
@@ -691,6 +691,7 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
691691
else if (atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_URIGHT_SHIFT;
692692
else if (atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_URIGHT_SHIFT;
693693
else if (atype == MONO_TYPE_U4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_URIGHT_SHIFT;
694+
else if (atype == MONO_TYPE_U8) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_URIGHT_SHIFT;
694695
break;
695696
case SN_Shuffle:
696697
simd_opcode = MINT_SIMD_INTRINS_P_PP;
@@ -1163,6 +1164,9 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
11631164
case SN_Equals:
11641165
cmethod_name = "CompareEqual";
11651166
break;
1167+
case SN_ExtractMostSignificantBits:
1168+
cmethod_name = "Bitmask";
1169+
break;
11661170
case SN_BitwiseAnd:
11671171
case SN_op_BitwiseAnd:
11681172
cmethod_name = "And";
@@ -1177,6 +1181,8 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
11771181
break;
11781182
case SN_Load:
11791183
case SN_LoadUnsafe:
1184+
if (csignature->param_count != 1)
1185+
return FALSE;
11801186
cmethod_name = "LoadVector128";
11811187
break;
11821188
case SN_Round:
@@ -1229,6 +1235,7 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
12291235
break;
12301236
case SN_ConvertToInt32:
12311237
cmethod_name = "ConvertToInt32Saturate";
1238+
break;
12321239
case SN_ShiftLeft:
12331240
case SN_ShiftRightLogical:
12341241
case SN_ShiftRightArithmetic:

0 commit comments

Comments
 (0)