[wasm] Add extending conversions to PackedSimd (#86252)
authorRadek Doulik <radek.doulik@gmail.com>
Mon, 15 May 2023 20:17:35 +0000 (22:17 +0200)
committerGitHub <noreply@github.com>
Mon, 15 May 2023 20:17:35 +0000 (22:17 +0200)
* [wasm] Add extending conversions to PackedSimd

* Feedback

src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.PlatformNotSupported.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs
src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs
src/mono/mono/mini/mini-llvm.c
src/mono/mono/mini/mini-ops.h
src/mono/mono/mini/simd-intrinsics.c

index aa10a81..a460ad4 100644 (file)
@@ -464,5 +464,33 @@ namespace System.Runtime.Intrinsics.Wasm
 
         internal static Vector128<byte>   ConvertNarrowingUnsignedSaturate(Vector128<short> lower, Vector128<short> upper) { throw new PlatformNotSupportedException(); }
         internal static Vector128<ushort> ConvertNarrowingUnsignedSaturate(Vector128<int>   lower, Vector128<int>   upper) { throw new PlatformNotSupportedException(); }
+
+        public static Vector128<short>  SignExtendWideningLower(Vector128<sbyte>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ushort> SignExtendWideningLower(Vector128<byte>   value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<int>    SignExtendWideningLower(Vector128<short>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<uint>   SignExtendWideningLower(Vector128<ushort> value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<long>   SignExtendWideningLower(Vector128<int>    value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ulong>  SignExtendWideningLower(Vector128<uint>   value) { throw new PlatformNotSupportedException(); }
+
+        public static Vector128<short>  SignExtendWideningUpper(Vector128<sbyte>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ushort> SignExtendWideningUpper(Vector128<byte>   value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<int>    SignExtendWideningUpper(Vector128<short>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<uint>   SignExtendWideningUpper(Vector128<ushort> value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<long>   SignExtendWideningUpper(Vector128<int>    value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ulong>  SignExtendWideningUpper(Vector128<uint>   value) { throw new PlatformNotSupportedException(); }
+
+        public static Vector128<short>  ZeroExtendWideningLower(Vector128<sbyte>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ushort> ZeroExtendWideningLower(Vector128<byte>   value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<int>    ZeroExtendWideningLower(Vector128<short>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<uint>   ZeroExtendWideningLower(Vector128<ushort> value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<long>   ZeroExtendWideningLower(Vector128<int>    value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ulong>  ZeroExtendWideningLower(Vector128<uint>   value) { throw new PlatformNotSupportedException(); }
+
+        public static Vector128<short>  ZeroExtendWideningUpper(Vector128<sbyte>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ushort> ZeroExtendWideningUpper(Vector128<byte>   value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<int>    ZeroExtendWideningUpper(Vector128<short>  value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<uint>   ZeroExtendWideningUpper(Vector128<ushort> value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<long>   ZeroExtendWideningUpper(Vector128<int>    value) { throw new PlatformNotSupportedException(); }
+        public static Vector128<ulong>  ZeroExtendWideningUpper(Vector128<uint>   value) { throw new PlatformNotSupportedException(); }
     }
 }
index 9f9d481..416e2f3 100644 (file)
@@ -1949,5 +1949,129 @@ namespace System.Runtime.Intrinsics.Wasm
         /// </summary>
         [Intrinsic]
         internal static Vector128<ushort> ConvertNarrowingUnsignedSaturate(Vector128<int>  lower, Vector128<int>   upper) => ConvertNarrowingUnsignedSaturate(lower, upper);
+
+        /// <summary>
+        ///   i16x8.extend_low_i8x16_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<short>  SignExtendWideningLower(Vector128<sbyte>  value) => SignExtendWideningLower(value);
+        /// <summary>
+        ///   i16x8.extend_low_i8x16_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ushort> SignExtendWideningLower(Vector128<byte>   value) => SignExtendWideningLower(value);
+        /// <summary>
+        ///   i32x4.extend_low_i16x8_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<int>    SignExtendWideningLower(Vector128<short>  value) => SignExtendWideningLower(value);
+        /// <summary>
+        ///   i32x4.extend_low_i16x8_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<uint>   SignExtendWideningLower(Vector128<ushort> value) => SignExtendWideningLower(value);
+        /// <summary>
+        ///   i64x2.extend_low_i32x4_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<long>   SignExtendWideningLower(Vector128<int>    value) => SignExtendWideningLower(value);
+        /// <summary>
+        ///   i64x2.extend_low_i32x4_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ulong>  SignExtendWideningLower(Vector128<uint>   value) => SignExtendWideningLower(value);
+
+        /// <summary>
+        ///   i16x8.extend_high_i8x16_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<short>  SignExtendWideningUpper(Vector128<sbyte>  value) => SignExtendWideningUpper(value);
+        /// <summary>
+        ///   i16x8.extend_high_i8x16_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ushort> SignExtendWideningUpper(Vector128<byte>   value) => SignExtendWideningUpper(value);
+        /// <summary>
+        ///   i32x4.extend_high_i16x8_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<int>    SignExtendWideningUpper(Vector128<short>  value) => SignExtendWideningUpper(value);
+        /// <summary>
+        ///   i32x4.extend_high_i16x8_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<uint>   SignExtendWideningUpper(Vector128<ushort> value) => SignExtendWideningUpper(value);
+        /// <summary>
+        ///   i64x2.extend_high_i32x4_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<long>   SignExtendWideningUpper(Vector128<int>    value) => SignExtendWideningUpper(value);
+        /// <summary>
+        ///   i64x2.extend_high_i32x4_s
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ulong>  SignExtendWideningUpper(Vector128<uint>   value) => SignExtendWideningUpper(value);
+
+        /// <summary>
+        ///   i16x8.extend_low_i8x16_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<short>  ZeroExtendWideningLower(Vector128<sbyte>  value) => ZeroExtendWideningLower(value);
+        /// <summary>
+        ///   i16x8.extend_low_i8x16_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ushort> ZeroExtendWideningLower(Vector128<byte>   value) => ZeroExtendWideningLower(value);
+        /// <summary>
+        ///   i32x4.extend_low_i16x8_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<int>    ZeroExtendWideningLower(Vector128<short>  value) => ZeroExtendWideningLower(value);
+        /// <summary>
+        ///   i32x4.extend_low_i16x8_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<uint>   ZeroExtendWideningLower(Vector128<ushort> value) => ZeroExtendWideningLower(value);
+        /// <summary>
+        ///   i64x2.extend_low_i32x4_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<long>   ZeroExtendWideningLower(Vector128<int>    value) => ZeroExtendWideningLower(value);
+        /// <summary>
+        ///   i64x2.extend_low_i32x4_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ulong>  ZeroExtendWideningLower(Vector128<uint>   value) => ZeroExtendWideningLower(value);
+
+        /// <summary>
+        ///   i16x8.extend_high_i8x16_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<short>  ZeroExtendWideningUpper(Vector128<sbyte>  value) => ZeroExtendWideningUpper(value);
+        /// <summary>
+        ///   i16x8.extend_high_i8x16_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ushort> ZeroExtendWideningUpper(Vector128<byte>   value) => ZeroExtendWideningUpper(value);
+        /// <summary>
+        ///   i32x4.extend_high_i16x8_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<int>    ZeroExtendWideningUpper(Vector128<short>  value) => ZeroExtendWideningUpper(value);
+        /// <summary>
+        ///   i32x4.extend_high_i16x8_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<uint>   ZeroExtendWideningUpper(Vector128<ushort> value) => ZeroExtendWideningUpper(value);
+        /// <summary>
+        ///   i64x2.extend_high_i32x4_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<long>   ZeroExtendWideningUpper(Vector128<int>    value) => ZeroExtendWideningUpper(value);
+        /// <summary>
+        ///   i64x2.extend_high_i32x4_u
+        /// </summary>
+        [Intrinsic]
+        public static Vector128<ulong>  ZeroExtendWideningUpper(Vector128<uint>   value) => ZeroExtendWideningUpper(value);
     }
 }
index 6153a61..3ba9098 100644 (file)
@@ -6600,5 +6600,29 @@ namespace System.Runtime.Intrinsics.Wasm
         public static Vector128<double> ConvertToDoubleLower(Vector128<float> value) { throw null; }
         public static Vector128<int>  ConvertToInt32Saturate(Vector128<float> value) { throw null; }
         public static Vector128<int>  ConvertToInt32Saturate(Vector128<double> value) { throw null; }
+        public static Vector128<short>  SignExtendWideningLower(Vector128<sbyte>  value) { throw null; }
+        public static Vector128<ushort> SignExtendWideningLower(Vector128<byte>   value) { throw null; }
+        public static Vector128<int>    SignExtendWideningLower(Vector128<short>  value) { throw null; }
+        public static Vector128<uint>   SignExtendWideningLower(Vector128<ushort> value) { throw null; }
+        public static Vector128<long>   SignExtendWideningLower(Vector128<int>    value) { throw null; }
+        public static Vector128<ulong>  SignExtendWideningLower(Vector128<uint>   value) { throw null; }
+        public static Vector128<short>  SignExtendWideningUpper(Vector128<sbyte>  value) { throw null; }
+        public static Vector128<ushort> SignExtendWideningUpper(Vector128<byte>   value) { throw null; }
+        public static Vector128<int>    SignExtendWideningUpper(Vector128<short>  value) { throw null; }
+        public static Vector128<uint>   SignExtendWideningUpper(Vector128<ushort> value) { throw null; }
+        public static Vector128<long>   SignExtendWideningUpper(Vector128<int>    value) { throw null; }
+        public static Vector128<ulong>  SignExtendWideningUpper(Vector128<uint>   value) { throw null; }
+        public static Vector128<short>  ZeroExtendWideningLower(Vector128<sbyte>  value) { throw null; }
+        public static Vector128<ushort> ZeroExtendWideningLower(Vector128<byte>   value) { throw null; }
+        public static Vector128<int>    ZeroExtendWideningLower(Vector128<short>  value) { throw null; }
+        public static Vector128<uint>   ZeroExtendWideningLower(Vector128<ushort> value) { throw null; }
+        public static Vector128<long>   ZeroExtendWideningLower(Vector128<int>    value) { throw null; }
+        public static Vector128<ulong>  ZeroExtendWideningLower(Vector128<uint>   value) { throw null; }
+        public static Vector128<short>  ZeroExtendWideningUpper(Vector128<sbyte>  value) { throw null; }
+        public static Vector128<ushort> ZeroExtendWideningUpper(Vector128<byte>   value) { throw null; }
+        public static Vector128<int>    ZeroExtendWideningUpper(Vector128<short>  value) { throw null; }
+        public static Vector128<uint>   ZeroExtendWideningUpper(Vector128<ushort> value) { throw null; }
+        public static Vector128<long>   ZeroExtendWideningUpper(Vector128<int>    value) { throw null; }
+        public static Vector128<ulong>  ZeroExtendWideningUpper(Vector128<uint>   value) { throw null; }
     }
 }
index a1cebd3..85fec5b 100644 (file)
@@ -5207,6 +5207,14 @@ extract_low_elements (EmitContext *ctx, LLVMValueRef src_vec)
        return extract_half_elements (ctx, src_vec, FALSE);
 }
 
+static G_GNUC_UNUSED LLVMTypeRef extended_type (LLVMTypeRef src_t)
+{
+       int nelems = LLVMGetVectorSize (src_t) / 2;
+       unsigned int width = mono_llvm_get_prim_size_bits (LLVMGetElementType(src_t));
+       LLVMTypeRef int_t = LLVMIntType (width * 2);
+       return LLVMVectorType (int_t, nelems);
+}
+
 static LLVMValueRef
 keep_lowest_element (EmitContext *ctx, LLVMTypeRef dst_t, LLVMValueRef vec)
 {
@@ -9942,6 +9950,17 @@ MONO_RESTORE_WARNING
                }
 #endif
 #if defined(TARGET_WASM)
+               case OP_WASM_SIMD_SEXT_LOWER:
+               case OP_WASM_SIMD_SEXT_UPPER:
+               case OP_WASM_SIMD_ZEXT_LOWER:
+               case OP_WASM_SIMD_ZEXT_UPPER: {
+                       LLVMTypeRef ret_t = extended_type (LLVMTypeOf (lhs));
+                       gboolean upper = (ins->opcode == OP_WASM_SIMD_SEXT_UPPER || ins->opcode == OP_WASM_SIMD_ZEXT_UPPER);
+                       gboolean sext = (ins->opcode == OP_WASM_SIMD_SEXT_LOWER || ins->opcode == OP_WASM_SIMD_SEXT_UPPER);
+                       LLVMValueRef ext = upper ? extract_high_elements (ctx, lhs) : extract_low_elements (ctx, lhs);
+                       values [ins->dreg] = sext ? LLVMBuildSExt (builder, ext, ret_t, "") : LLVMBuildZExt (builder, ext, ret_t, "");
+                       break;
+               }
                case OP_WASM_SIMD_CONV_R8_TO_R4: {
                        LLVMValueRef val = LLVMBuildFPTrunc (builder, lhs, v64_r4_t, "");
                        values [ins->dreg] = LLVMBuildShuffleVector (builder, val, LLVMConstNull(v64_r4_t), create_const_vector_4_i32 (0, 1, 2, 3), "");
@@ -10068,11 +10087,7 @@ MONO_RESTORE_WARNING
                case OP_WASM_EXTMUL_UPPER_U:
                case OP_WASM_EXTMUL_LOWER:
                case OP_WASM_EXTMUL_UPPER: {
-                       LLVMTypeRef src_t = LLVMTypeOf (lhs);
-                       int nelems = LLVMGetVectorSize (src_t) / 2;
-                       unsigned int width = mono_llvm_get_prim_size_bits (LLVMGetElementType(src_t));
-                       LLVMTypeRef int_t = LLVMIntType (width * 2);
-                       LLVMTypeRef ret_t = LLVMVectorType (int_t, nelems);
+                       LLVMTypeRef ret_t = extended_type (LLVMTypeOf (lhs));
                        int lower = ins->opcode == OP_WASM_EXTMUL_LOWER || ins->opcode == OP_WASM_EXTMUL_LOWER_U;
                        gboolean is_unsigned = ins->opcode == OP_WASM_EXTMUL_LOWER_U || ins->opcode == OP_WASM_EXTMUL_UPPER_U;
                        LLVMValueRef part1 = lower ? extract_low_elements (ctx, lhs) : extract_high_elements(ctx, lhs);
index 05f3c07..df1731f 100644 (file)
@@ -862,6 +862,10 @@ MINI_OP(OP_WASM_EXTMUL_UPPER_U, "wasm_extmul_upper_u", XREG, XREG, XREG)
 MINI_OP(OP_WASM_SIMD_CONV_R8_TO_R4, "wasm_simd_conv_r8_to_r4", XREG, XREG, NONE)
 MINI_OP(OP_WASM_SIMD_CONV_R8_TO_I4_ZERO, "wasm_simd_conv_r8_to_i4_zero", XREG, XREG, NONE)
 MINI_OP(OP_WASM_SIMD_CONV_U4_TO_R8_LOW, "wasm_simd_conv_u4_to_r8_low", XREG, XREG, NONE)
+MINI_OP(OP_WASM_SIMD_SEXT_LOWER, "wasm_simd_ext_lower_s", XREG, XREG, NONE)
+MINI_OP(OP_WASM_SIMD_SEXT_UPPER, "wasm_simd_ext_upper_s", XREG, XREG, NONE)
+MINI_OP(OP_WASM_SIMD_ZEXT_LOWER, "wasm_simd_ext_lower_u", XREG, XREG, NONE)
+MINI_OP(OP_WASM_SIMD_ZEXT_UPPER, "wasm_simd_ext_upper_u", XREG, XREG, NONE)
 #endif
 
 #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_WASM)
index dd35ca5..9de5495 100644 (file)
@@ -5114,6 +5114,8 @@ static SimdIntrinsic packedsimd_methods [] = {
        {SN_ShiftRightArithmetic, OP_SIMD_SSHR},
        {SN_ShiftRightLogical, OP_SIMD_USHR},
        {SN_Shuffle, OP_WASM_SIMD_SHUFFLE},
+       {SN_SignExtendWideningLower, OP_WASM_SIMD_SEXT_LOWER},
+       {SN_SignExtendWideningUpper, OP_WASM_SIMD_SEXT_UPPER},
        {SN_Splat},
        {SN_Sqrt},
        {SN_Subtract},
@@ -5121,6 +5123,8 @@ static SimdIntrinsic packedsimd_methods [] = {
        {SN_Swizzle, OP_WASM_SIMD_SWIZZLE},
        {SN_Truncate, OP_XOP_OVR_X_X, INTRINS_SIMD_TRUNC},
        {SN_Xor, OP_XBINOP_FORCEINT, XBINOP_FORCEINT_XOR},
+       {SN_ZeroExtendWideningLower, OP_WASM_SIMD_ZEXT_LOWER},
+       {SN_ZeroExtendWideningUpper, OP_WASM_SIMD_ZEXT_UPPER},
        {SN_get_IsSupported},
 };