From 1d2a2036004ad763b488963a0be44c806d6cd31a Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 29 May 2023 16:48:21 +0300 Subject: [PATCH] [mono][interp] Use vectorized opcodes for Vector operators (#86859) * [mono][interp] Remove some duplicated code in transform-simd.c * [mono][interp] Intrinsify Vector operators They do the same thing as the Vector128 counterpart * [mono][interp] Add missing simd opcodes --- src/mono/mono/mini/interp/transform-simd.c | 493 +++++++++++---------- 1 file changed, 266 insertions(+), 227 deletions(-) diff --git a/src/mono/mono/mini/interp/transform-simd.c b/src/mono/mono/mini/interp/transform-simd.c index c74caaf82d6d7..0ed06ab397135 100644 --- a/src/mono/mono/mini/interp/transform-simd.c +++ b/src/mono/mono/mini/interp/transform-simd.c @@ -89,6 +89,27 @@ static guint16 sri_vector128_t_methods [] = { SN_op_UnsignedRightShift, }; +static guint16 sn_vector_t_methods [] = { + SN_get_AllBitsSet, + SN_get_Count, + SN_get_One, + SN_get_Zero, + SN_op_Addition, + SN_op_BitwiseAnd, + SN_op_BitwiseOr, + SN_op_Division, + SN_op_Equality, + SN_op_ExclusiveOr, + SN_op_Inequality, + SN_op_LeftShift, + SN_op_Multiply, + SN_op_OnesComplement, + SN_op_RightShift, + SN_op_Subtraction, + SN_op_UnaryNegation, + SN_op_UnsignedRightShift, +}; + static guint16 sri_packedsimd_methods [] = { SN_Add, SN_And, @@ -155,22 +176,154 @@ static int sri_packedsimd_offset_from_atype [] = { static const int sri_packedsimd_offset_from_atype_length = sizeof(sri_packedsimd_offset_from_atype) / sizeof(sri_packedsimd_offset_from_atype[0]); #endif // HOST_BROWSER +// Returns if opcode was added static gboolean -emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *csignature) +emit_common_simd_operations (TransformData *td, int id, int atype, int vector_size, int arg_size, int scalar_arg, gint16 *simd_opcode, gint16 *simd_intrins) { - int id = lookup_intrins (sri_vector128_methods, sizeof (sri_vector128_methods), cmethod); - if (id == -1) - return FALSE; - - MonoClass *vector_klass = mono_class_from_mono_type_internal (csignature->ret); - if (id == SN_get_IsHardwareAccelerated) { - interp_add_ins (td, MINT_LDC_I4_1); - goto opcode_added; + switch (id) { + case SN_get_AllBitsSet: { + interp_add_ins (td, MINT_SIMD_V128_LDC); + guint16 *data = &td->last_ins->data [0]; + for (int i = 0; i < vector_size / sizeof (guint16); i++) + data [i] = 0xffff; + return TRUE; + } + case SN_get_Count: + interp_add_ins (td, MINT_LDC_I4_S); + td->last_ins->data [0] = vector_size / arg_size; + return TRUE; + case SN_get_One: + if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) { + interp_add_ins (td, MINT_SIMD_V128_LDC); + gint8 *data = (gint8*)&td->last_ins->data [0]; + for (int i = 0; i < vector_size / arg_size; i++) + data [i] = 1; + return TRUE; + } else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) { + interp_add_ins (td, MINT_SIMD_V128_LDC); + gint16 *data = (gint16*)&td->last_ins->data [0]; + for (int i = 0; i < vector_size / arg_size; i++) + data [i] = 1; + return TRUE; + } else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) { + interp_add_ins (td, MINT_SIMD_V128_LDC); + gint32 *data = (gint32*)&td->last_ins->data [0]; + for (int i = 0; i < vector_size / arg_size; i++) + data [i] = 1; + return TRUE; + } else if (atype == MONO_TYPE_I8 || atype == MONO_TYPE_U8) { + interp_add_ins (td, MINT_SIMD_V128_LDC); + gint64 *data = (gint64*)&td->last_ins->data [0]; + for (int i = 0; i < vector_size / arg_size; i++) + data [i] = 1; + return TRUE; + } + break; + case SN_get_Zero: + interp_add_ins (td, MINT_INITLOCAL); + td->last_ins->data [0] = SIZEOF_V128; + return TRUE; + case SN_op_Addition: + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_ADD; + else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_ADD; + else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_ADD; + else if (atype == MONO_TYPE_R4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_ADD; + break; + case SN_op_BitwiseAnd: + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + *simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_AND; + break; + case SN_op_BitwiseOr: + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + *simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_OR; + break; + case SN_op_Equality: + if (atype != MONO_TYPE_R4 && atype != MONO_TYPE_R8) { + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + *simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_EQUALITY; + } + break; + case SN_op_ExclusiveOr: + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + *simd_intrins = INTERP_SIMD_INTRINSIC_V128_EXCLUSIVE_OR; + break; + case SN_op_Inequality: + if (atype != MONO_TYPE_R4 && atype != MONO_TYPE_R8) { + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + *simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_INEQUALITY; + } + break; + case SN_op_LeftShift: + if (scalar_arg != 1) + break; + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (arg_size == 1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_LEFT_SHIFT; + else if (arg_size == 2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_LEFT_SHIFT; + else if (arg_size == 4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_LEFT_SHIFT; + else if (arg_size == 8) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_LEFT_SHIFT; + break; + case SN_op_Division: + if (scalar_arg != -1) + break; + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (atype == MONO_TYPE_R4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_DIVISION; + break; + case SN_op_Multiply: + if (scalar_arg != -1) + break; + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_MULTIPLY; + else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_MULTIPLY; + else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_MULTIPLY; + else if (atype == MONO_TYPE_R4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_MULTIPLY; + break; + case SN_op_OnesComplement: + *simd_opcode = MINT_SIMD_INTRINS_P_P; + *simd_intrins = INTERP_SIMD_INTRINSIC_V128_ONES_COMPLEMENT; + break; + case SN_op_RightShift: + if (scalar_arg != 1) + break; + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (atype == MONO_TYPE_I1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_RIGHT_SHIFT; + else if (atype == MONO_TYPE_I2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_RIGHT_SHIFT; + else if (atype == MONO_TYPE_I4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_RIGHT_SHIFT; + 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; + break; + case SN_op_Subtraction: + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_SUB; + else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_SUB; + else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_SUB; + else if (atype == MONO_TYPE_R4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_SUB; + break; + case SN_op_UnaryNegation: + *simd_opcode = MINT_SIMD_INTRINS_P_P; + if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_NEGATION; + else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_NEGATION; + else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_NEGATION; + break; + case SN_op_UnsignedRightShift: + if (scalar_arg != 1) + break; + *simd_opcode = MINT_SIMD_INTRINS_P_PP; + if (arg_size == 1) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_URIGHT_SHIFT; + else if (arg_size == 2) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_URIGHT_SHIFT; + else if (arg_size == 4) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_URIGHT_SHIFT; + else if (arg_size == 8) *simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_URIGHT_SHIFT; + break; } - gint16 simd_opcode = -1; - gint16 simd_intrins = -1; - if (!m_class_is_simd_type (vector_klass)) + return FALSE; +} + +static gboolean +get_common_simd_info (MonoClass *vector_klass, MonoMethodSignature *csignature, MonoTypeEnum *atype, int *vector_size, int *arg_size, int *scalar_arg) +{ + if (!m_class_is_simd_type (vector_klass) && csignature->param_count) vector_klass = mono_class_from_mono_type_internal (csignature->params [0]); if (!m_class_is_simd_type (vector_klass)) return FALSE; @@ -178,18 +331,66 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature MonoType *arg_type = mono_class_get_context (vector_klass)->class_inst->type_argv [0]; if (!mono_type_is_primitive (arg_type)) return FALSE; - MonoTypeEnum atype = arg_type->type; - if (atype == MONO_TYPE_BOOLEAN) + *atype = arg_type->type; + if (*atype == MONO_TYPE_BOOLEAN) return FALSE; - int vector_size = mono_class_value_size (vector_klass, NULL); - int arg_size = mono_class_value_size (mono_class_from_mono_type_internal (arg_type), NULL); - g_assert (vector_size == SIZEOF_V128); + *vector_size = mono_class_value_size (vector_klass, NULL); + g_assert (*vector_size == SIZEOF_V128); + if (arg_size) + *arg_size = mono_class_value_size (mono_class_from_mono_type_internal (arg_type), NULL); - int scalar_arg = -1; + *scalar_arg = -1; for (int i = 0; i < csignature->param_count; i++) { if (csignature->params [i]->type != MONO_TYPE_GENERICINST) - scalar_arg = i; + *scalar_arg = i; + } + + return TRUE; +} + +static void +emit_common_simd_epilogue (TransformData *td, MonoClass *vector_klass, MonoMethodSignature *csignature, int vector_size) +{ + td->sp -= csignature->param_count; + for (int i = 0; i < csignature->param_count; i++) + td->last_ins->sregs [i] = td->sp [i].local; + + g_assert (csignature->ret->type != MONO_TYPE_VOID); + int ret_mt = mono_mint_type (csignature->ret); + if (ret_mt == MINT_TYPE_VT) { + // For these intrinsics, if we return a VT then it is a V128 + push_type_vt (td, vector_klass, vector_size); + } else { + push_simple_type (td, stack_type [ret_mt]); } + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 5; +} + +static gboolean +emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *csignature) +{ + int id = lookup_intrins (sri_vector128_methods, sizeof (sri_vector128_methods), cmethod); + if (id == -1) + return FALSE; + + MonoClass *vector_klass = NULL; + int vector_size = 0; + + if (id == SN_get_IsHardwareAccelerated) { + interp_add_ins (td, MINT_LDC_I4_1); + goto opcode_added; + } + + gint16 simd_opcode = -1; + gint16 simd_intrins = -1; + + vector_klass = mono_class_from_mono_type_internal (csignature->ret); + + MonoTypeEnum atype; + int arg_size, scalar_arg; + if (!get_common_simd_info (vector_klass, csignature, &atype, &vector_size, &arg_size, &scalar_arg)) + return FALSE; switch (id) { case SN_AndNot: @@ -326,20 +527,7 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature td->last_ins->data [0] = simd_intrins; opcode_added: - td->sp -= csignature->param_count; - for (int i = 0; i < csignature->param_count; i++) - td->last_ins->sregs [i] = td->sp [i].local; - - g_assert (csignature->ret->type != MONO_TYPE_VOID); - int ret_mt = mono_mint_type (csignature->ret); - if (ret_mt == MINT_TYPE_VT) { - // For these intrinsics, if we return a VT then it is a V128 - push_type_vt (td, vector_klass, vector_size); - } else { - push_simple_type (td, stack_type [ret_mt]); - } - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); - td->ip += 5; + emit_common_simd_epilogue (td, vector_klass, csignature, vector_size); return TRUE; } @@ -355,179 +543,55 @@ emit_sri_vector128_t (TransformData *td, MonoMethod *cmethod, MonoMethodSignatur // First argument is always vector MonoClass *vector_klass = cmethod->klass; - MonoType *arg_type = mono_class_get_context (vector_klass)->class_inst->type_argv [0]; - if (!mono_type_is_primitive (arg_type)) + + MonoTypeEnum atype; + int vector_size, arg_size, scalar_arg; + if (!get_common_simd_info (vector_klass, csignature, &atype, &vector_size, &arg_size, &scalar_arg)) return FALSE; - MonoTypeEnum atype = arg_type->type; - if (atype == MONO_TYPE_BOOLEAN) + + if (emit_common_simd_operations (td, id, atype, vector_size, arg_size, scalar_arg, &simd_opcode, &simd_intrins)) + goto opcode_added; + + if (simd_opcode == -1 || simd_intrins == -1) return FALSE; - int vector_size = mono_class_value_size (vector_klass, NULL); - int arg_size = mono_class_value_size (mono_class_from_mono_type_internal (arg_type), NULL); - g_assert (vector_size == SIZEOF_V128); - int scalar_arg = -1; - for (int i = 0; i < csignature->param_count; i++) { - if (csignature->params [i]->type != MONO_TYPE_GENERICINST) - scalar_arg = i; - } + interp_add_ins (td, simd_opcode); + td->last_ins->data [0] = simd_intrins; - switch (id) { - case SN_get_AllBitsSet: { - interp_add_ins (td, MINT_SIMD_V128_LDC); - guint16 *data = &td->last_ins->data [0]; - for (int i = 0; i < vector_size / sizeof (guint16); i++) - data [i] = 0xffff; - goto opcode_added; - } - case SN_get_Count: - interp_add_ins (td, MINT_LDC_I4_S); - td->last_ins->data [0] = vector_size / arg_size; - goto opcode_added; - case SN_get_One: - if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) { - interp_add_ins (td, MINT_SIMD_V128_LDC); - gint8 *data = (gint8*)&td->last_ins->data [0]; - for (int i = 0; i < vector_size / arg_size; i++) - data [i] = 1; - goto opcode_added; - } else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) { - interp_add_ins (td, MINT_SIMD_V128_LDC); - gint16 *data = (gint16*)&td->last_ins->data [0]; - for (int i = 0; i < vector_size / arg_size; i++) - data [i] = 1; - goto opcode_added; - } else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) { - interp_add_ins (td, MINT_SIMD_V128_LDC); - gint32 *data = (gint32*)&td->last_ins->data [0]; - for (int i = 0; i < vector_size / arg_size; i++) - data [i] = 1; - goto opcode_added; - } else if (atype == MONO_TYPE_I8 || atype == MONO_TYPE_U8) { - interp_add_ins (td, MINT_SIMD_V128_LDC); - gint64 *data = (gint64*)&td->last_ins->data [0]; - for (int i = 0; i < vector_size / arg_size; i++) - data [i] = 1; - goto opcode_added; - } - break; - case SN_get_Zero: - interp_add_ins (td, MINT_INITLOCAL); - td->last_ins->data [0] = SIZEOF_V128; - goto opcode_added; - case SN_op_Addition: - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_ADD; - else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_ADD; - else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_ADD; - break; - case SN_op_BitwiseAnd: - simd_opcode = MINT_SIMD_INTRINS_P_PP; - simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_AND; - break; - case SN_op_BitwiseOr: - simd_opcode = MINT_SIMD_INTRINS_P_PP; - simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_OR; - break; - case SN_op_Equality: - if (atype != MONO_TYPE_R4 && atype != MONO_TYPE_R8) { - simd_opcode = MINT_SIMD_INTRINS_P_PP; - simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_EQUALITY; - } - break; - case SN_op_ExclusiveOr: - simd_opcode = MINT_SIMD_INTRINS_P_PP; - simd_intrins = INTERP_SIMD_INTRINSIC_V128_EXCLUSIVE_OR; - break; - case SN_op_Inequality: - if (atype != MONO_TYPE_R4 && atype != MONO_TYPE_R8) { - simd_opcode = MINT_SIMD_INTRINS_P_PP; - simd_intrins = INTERP_SIMD_INTRINSIC_V128_BITWISE_INEQUALITY; - } - break; - case SN_op_LeftShift: - if (scalar_arg != 1) - return FALSE; - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (arg_size == 1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_LEFT_SHIFT; - else if (arg_size == 2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_LEFT_SHIFT; - else if (arg_size == 4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_LEFT_SHIFT; - else if (arg_size == 8) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_LEFT_SHIFT; - break; - case SN_op_Division: - if (scalar_arg != -1) - return FALSE; - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (atype == MONO_TYPE_R4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_DIVISION; - break; - case SN_op_Multiply: - if (scalar_arg != -1) - return FALSE; - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_MULTIPLY; - else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_MULTIPLY; - else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_MULTIPLY; - else if (atype == MONO_TYPE_R4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_R4_MULTIPLY; - break; - case SN_op_OnesComplement: - simd_opcode = MINT_SIMD_INTRINS_P_P; - simd_intrins = INTERP_SIMD_INTRINSIC_V128_ONES_COMPLEMENT; - break; - case SN_op_RightShift: - if (scalar_arg != 1) - return FALSE; - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (atype == MONO_TYPE_I1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_RIGHT_SHIFT; - else if (atype == MONO_TYPE_I2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_RIGHT_SHIFT; - else if (atype == MONO_TYPE_I4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_RIGHT_SHIFT; - 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; - break; - case SN_op_Subtraction: - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_SUB; - else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_SUB; - else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_SUB; - break; - case SN_op_UnaryNegation: - simd_opcode = MINT_SIMD_INTRINS_P_P; - if (atype == MONO_TYPE_I1 || atype == MONO_TYPE_U1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_NEGATION; - else if (atype == MONO_TYPE_I2 || atype == MONO_TYPE_U2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_NEGATION; - else if (atype == MONO_TYPE_I4 || atype == MONO_TYPE_U4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_NEGATION; - break; - case SN_op_UnsignedRightShift: - if (scalar_arg != 1) - return FALSE; - simd_opcode = MINT_SIMD_INTRINS_P_PP; - if (arg_size == 1) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I1_URIGHT_SHIFT; - else if (arg_size == 2) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I2_URIGHT_SHIFT; - else if (arg_size == 4) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I4_URIGHT_SHIFT; - else if (arg_size == 8) simd_intrins = INTERP_SIMD_INTRINSIC_V128_I8_URIGHT_SHIFT; - break; - } +opcode_added: + emit_common_simd_epilogue (td, vector_klass, csignature, vector_size); + return TRUE; +} - if (simd_opcode == -1 || simd_intrins == -1) { +static gboolean +emit_sn_vector_t (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *csignature) +{ + int id = lookup_intrins (sn_vector_t_methods, sizeof (sn_vector_t_methods), cmethod); + if (id == -1) + return FALSE; + + gint16 simd_opcode = -1; + gint16 simd_intrins = -1; + + // First argument is always vector + MonoClass *vector_klass = cmethod->klass; + + MonoTypeEnum atype; + int vector_size, arg_size, scalar_arg; + if (!get_common_simd_info (vector_klass, csignature, &atype, &vector_size, &arg_size, &scalar_arg)) + return FALSE; + + if (emit_common_simd_operations (td, id, atype, vector_size, arg_size, scalar_arg, &simd_opcode, &simd_intrins)) + goto opcode_added; + + if (simd_opcode == -1 || simd_intrins == -1) return FALSE; - } interp_add_ins (td, simd_opcode); td->last_ins->data [0] = simd_intrins; opcode_added: - td->sp -= csignature->param_count; - for (int i = 0; i < csignature->param_count; i++) - td->last_ins->sregs [i] = td->sp [i].local; - - g_assert (csignature->ret->type != MONO_TYPE_VOID); - int ret_mt = mono_mint_type (csignature->ret); - if (ret_mt == MINT_TYPE_VT) { - // For these intrinsics, if we return a VT then it is a V128 - push_type_vt (td, vector_klass, vector_size); - } else { - push_simple_type (td, stack_type [ret_mt]); - } - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); - td->ip += 5; + emit_common_simd_epilogue (td, vector_klass, csignature, vector_size); return TRUE; } @@ -584,27 +648,12 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature gint16 simd_opcode = -1; gint16 simd_intrins = -1; - if (!m_class_is_simd_type (vector_klass)) - vector_klass = mono_class_from_mono_type_internal (csignature->params [0]); - if (!m_class_is_simd_type (vector_klass)) - return FALSE; - - vector_size = mono_class_value_size (vector_klass, NULL); - g_assert (vector_size == SIZEOF_V128); - MonoType *arg_type = mono_class_get_context (vector_klass)->class_inst->type_argv [0]; - if (!mono_type_is_primitive (arg_type)) - return FALSE; - MonoTypeEnum atype = arg_type->type; - if (atype == MONO_TYPE_BOOLEAN) + MonoTypeEnum atype; + int scalar_arg; + if (!get_common_simd_info (vector_klass, csignature, &atype, &vector_size, NULL, &scalar_arg)) return FALSE; - int scalar_arg = -1; - for (int i = 0; i < csignature->param_count; i++) { - if (csignature->params [i]->type != MONO_TYPE_GENERICINST) - scalar_arg = i; - } - switch (id) { case SN_Splat: { simd_opcode = MINT_SIMD_INTRINS_P_P; @@ -707,20 +756,7 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature #endif // HOST_BROWSER opcode_added: - td->sp -= csignature->param_count; - for (int i = 0; i < csignature->param_count; i++) - td->last_ins->sregs [i] = td->sp [i].local; - - g_assert (csignature->ret->type != MONO_TYPE_VOID); - int ret_mt = mono_mint_type (csignature->ret); - if (ret_mt == MINT_TYPE_VT) { - // For these intrinsics, if we return a VT then it is a V128 - push_type_vt (td, vector_klass, vector_size); - } else { - push_simple_type (td, stack_type [ret_mt]); - } - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); - td->ip += 5; + emit_common_simd_epilogue (td, vector_klass, csignature, vector_size); return TRUE; } @@ -742,6 +778,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 (!strcmp (class_ns, "System.Numerics")) { + if (!strcmp (class_name, "Vector`1")) + return emit_sn_vector_t (td, cmethod, csignature); } else if (!strcmp (class_ns, "System.Runtime.Intrinsics.Wasm")) { if (!strcmp (class_name, "PackedSimd")) return emit_sri_packedsimd (td, cmethod, csignature);