From dddd6a1c2ddff3b64d4f66dc413d00caf79cb04b Mon Sep 17 00:00:00 2001 From: saitama951 Date: Tue, 5 Aug 2025 07:12:13 +0000 Subject: [PATCH 1/4] [S390X] Add simd fallback support for unsupported s390x architectures Vector facility was introduced in the z13, which majorly introduces vector int/short/long/double variants of the vector instructions. with the release of z14 we introduced vector float variant as part of vector enhancement facility 1. This patch majorly supports z13 and previous generations. --- src/mono/mono/mini/simd-intrinsics.c | 113 +++++++++++++++++++++++-- src/mono/mono/utils/mono-hwcap-s390x.c | 1 + src/mono/mono/utils/mono-hwcap-vars.h | 1 + 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 88143637310ef9..b8f78487cd85e6 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2112,6 +2112,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } #elif defined(TARGET_S390X) if (type_enum_is_float(arg0_type)) { + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; return emit_simd_ins_for_sig (cfg, klass, arg0_type == MONO_TYPE_R8 ? OP_S390_VFLPDB : OP_S390_VFLPSB, -1, arg0_type, fsig, args); } else { return emit_simd_ins_for_sig (cfg, klass, OP_VECTOR_IABS, -1, arg0_type, fsig, args); @@ -2135,11 +2137,17 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi if (!is_element_type_primitive (fsig->params [0]) || !is_element_type_primitive (fsig->params [1])) return NULL; +#if defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative) || (id !=SN_Xor) || (id != SN_BitwiseAnd) || (id != SN_BitwiseOr)) && arg0_type == MONO_TYPE_R4) + return NULL; +#endif + #if !defined(TARGET_ARM64) && !defined(TARGET_S390X) if (((id == SN_Max) || (id == SN_Min)) && type_enum_is_float(arg0_type)) return NULL; #endif + return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); } case SN_Divide: { @@ -2149,7 +2157,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi if (!is_element_type_primitive (fsig->params [0]) || !(MONO_TYPE_IS_VECTOR_PRIMITIVE (fsig->params [1]) || is_element_type_primitive (fsig->params [1]))) return NULL; - +#if defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); } case SN_Multiply: { @@ -2170,7 +2181,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; } else if (!(is_element_type_primitive (fsig->params [0]) && is_element_type_primitive (fsig->params [1]))) return NULL; - +#if defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (vector_inner_type == MONO_TYPE_R4)) + return NULL; +#endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, vector_inner_type, id); } case SN_AndNot: { @@ -2198,13 +2212,17 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi int add_op; if (type_enum_is_float (arg0_type)) { +#if defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif mul_op = OP_FMUL; add_op = OP_FADD; } else { mul_op = OP_IMUL; add_op = OP_IADD; -#ifdef TARGET_ARM64 +#if defined(TARGET_ARM64) || defined(TARGET_S390X) if (!COMPILE_LLVM (cfg) && (arg0_type == MONO_TYPE_I8 || arg0_type == MONO_TYPE_U8 || arg0_type == MONO_TYPE_I || arg0_type == MONO_TYPE_U)) return NULL; #endif @@ -2274,6 +2292,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi int ceil_or_floor = id == SN_Ceiling ? 10 : 9; return emit_simd_ins_for_sig (cfg, klass, OP_SSE41_ROUNDP, ceil_or_floor, arg0_type, fsig, args); #elif defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; int ceil_or_floor = id == SN_Ceiling ? 6 : 7; switch (arg0_type){ case MONO_TYPE_R4: @@ -2464,6 +2484,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return emit_vector_create_scalar (cfg, vklass, etype, args [0], is_unsafe); } case SN_Dot: { +#if defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif return emit_dot (cfg, klass, fsig->params [0], arg0_type, args [0]->dreg, args [1]->dreg); } case SN_Equals: @@ -2472,6 +2496,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi if (!is_element_type_primitive (fsig->params [0])) return NULL; MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif if (id == SN_Equals) return emit_xcompare (cfg, klass, arg0_type, args [0], args [1]); @@ -2733,7 +2761,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_LessThanOrEqual: { if (!is_element_type_primitive (fsig->params [0])) return NULL; - +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif return emit_xcompare_for_intrinsic (cfg, klass, id, arg0_type, args [0], args [1]); } case SN_GreaterThanAll: @@ -2750,7 +2781,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi g_assert (fsig->param_count == 2 && fsig->ret->type == MONO_TYPE_BOOLEAN && mono_metadata_type_equal (fsig->params [0], fsig->params [1])); - +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif gboolean is_all = FALSE; switch (id) { case SN_GreaterThanAll: @@ -2857,6 +2891,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; if (!type_enum_is_float(arg0_type)) return emit_xzero (cfg, klass); +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif int op = -1; #if defined(TARGET_ARM64) || defined(TARGET_AMD64) || defined(TARGET_WASM) || defined(TARGET_S390X) op = OP_ONES_COMPLEMENT; @@ -2879,7 +2917,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return emit_xones (cfg, klass); } } - +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif MonoInst *arg0 = args [0]; MonoClass *op_klass = klass; @@ -2907,6 +2948,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_IsPositiveInfinity: { if (!is_element_type_primitive (fsig->params [0])) return NULL; +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif if (arg0_type == MONO_TYPE_R4) { guint32 value[4]; @@ -2984,6 +3029,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_IsZero: { if (!is_element_type_primitive (fsig->params [0])) return NULL; +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif return emit_xcompare (cfg, klass, arg0_type, args [0], emit_xzero (cfg, klass)); } case SN_Narrow: { @@ -3129,7 +3178,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_OnesComplement: { if (!is_element_type_primitive (fsig->params [0])) return NULL; +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (id == SN_Negate) && (arg0_type == MONO_TYPE_R4)) return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id); +#endif } case SN_Shuffle: { MonoType *etype = get_vector_t_elem_type (fsig->ret); @@ -3295,6 +3347,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return emit_simd_ins_for_sig (cfg, klass, OP_XOP_X_X, instc0, arg0_type, fsig, args); #elif defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; + int instc0 = arg0_type == MONO_TYPE_R4 ? OP_S390_VFSQSB : OP_S390_VFSQDB; return emit_simd_ins_for_sig (cfg, klass, instc0, 0, arg0_type, fsig, args); #else @@ -3792,6 +3847,10 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f if (fsig->param_count != 2 ) return NULL; arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID; +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && ((id !=SN_op_ExclusiveOr) || (id != SN_op_BitwiseAnd) || (id != SN_op_BitwiseOr)) && arg0_type == MONO_TYPE_R4) + return NULL; +#endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); } @@ -3800,6 +3859,10 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f if (fsig->param_count != 2 ) return NULL; MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif switch (id) { case SN_op_Equality: return emit_xequal (cfg, arg_class, arg0_type, args [0], args [1]); case SN_op_Inequality: return emit_not_xequal (cfg, arg_class, arg0_type, args [0], args [1]); @@ -3810,6 +3873,10 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f case SN_op_UnaryNegation: if (fsig->param_count != 1 ) return NULL; +#if defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1 && (id == SN_op_UnaryNegation) && (arg0_type == MONO_TYPE_R4)) + return NULL; +#endif return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id); case SN_op_UnaryPlus: if (fsig->param_count != 1) @@ -4150,10 +4217,18 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f #ifndef TARGET_ARM64 if ((id == SN_Max) || (id == SN_Min)) return NULL; +#endif +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative))) + return NULL; #endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, MONO_TYPE_R4, id); } case SN_Dot: { +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1) + return NULL; +#endif return emit_dot (cfg, klass, fsig->params [0], MONO_TYPE_R4, args [0]->dreg, args [1]->dreg); } case SN_Negate: @@ -4172,6 +4247,10 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f return emit_simd_ins_for_sig (cfg, cmethod->klass, OP_XOP_OVR_X_X, INTRINS_AARCH64_ADV_SIMD_FABS, MONO_TYPE_R4, fsig, args); #endif } +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1) + return NULL; +#endif // MAX(x,0-x) MonoInst *zero = emit_xzero (cfg, klass); MonoInst *neg = emit_simd_ins (cfg, klass, OP_XBINOP, zero->dreg, args [0]->dreg); @@ -4185,12 +4264,20 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f case SN_op_Equality: { if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type))) return NULL; +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1) + return NULL; +#endif MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); return emit_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]); } case SN_op_Inequality: { if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type))) return NULL; +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1) + return NULL; +#endif MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); return emit_not_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]); } @@ -4201,6 +4288,11 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f ins = emit_simd_ins (cfg, klass, OP_XOP_X_X, args [0]->dreg, -1); ins->inst_c0 = (IntrinsicId)INTRINS_SIMD_SQRT_R4; return ins; +#elif defined(TARGET_S390X) + if (!mono_hwcap_s390x_has_ve1) + return NULL; + ins = emit_simd_ins (cfg, klass, OP_S390_VFSQSB, args [0]->dreg, -1); + return ins; #else return NULL; #endif @@ -4215,6 +4307,10 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f if (id == SN_Clamp) return NULL; #endif +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1) + return NULL; +#endif MonoInst *max = emit_simd_ins (cfg, klass, OP_XBINOP, args[0]->dreg, args[1]->dreg); max->inst_c0 = OP_FMAX; @@ -6865,6 +6961,11 @@ static MonoInst* emit_simd_intrinsics (const char *class_ns, const char *class_name, MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { MonoInst *ins; +#ifdef TARGET_S390X + /* vector facility was introduced in z13 */ + if (!mono_hwcap_s390x_has_vec) + return NULL; +#endif if (cfg->opt & MONO_OPT_SIMD) { ins = arch_emit_simd_intrinsics (class_ns, class_name, cfg, cmethod, fsig, args); diff --git a/src/mono/mono/utils/mono-hwcap-s390x.c b/src/mono/mono/utils/mono-hwcap-s390x.c index ddc828bbc046a0..7f735066e238b8 100644 --- a/src/mono/mono/utils/mono-hwcap-s390x.c +++ b/src/mono/mono/utils/mono-hwcap-s390x.c @@ -157,6 +157,7 @@ mono_hwcap_arch_init (void) mono_hwcap_s390x_has_fpe = facs.fpe; mono_hwcap_s390x_has_vec = facs.vec; + mono_hwcap_s390x_has_ve1 = facs.ve1; mono_hwcap_s390x_has_mlt = facs.multi; mono_hwcap_s390x_has_ia = facs.ia; mono_hwcap_s390x_has_gie = facs.gie; diff --git a/src/mono/mono/utils/mono-hwcap-vars.h b/src/mono/mono/utils/mono-hwcap-vars.h index 98f4eb29115e83..391910a919c76e 100644 --- a/src/mono/mono/utils/mono-hwcap-vars.h +++ b/src/mono/mono/utils/mono-hwcap-vars.h @@ -54,6 +54,7 @@ MONO_HWCAP_VAR(riscv_has_stdext_v) #elif defined (TARGET_S390X) MONO_HWCAP_VAR(s390x_has_fpe) +MONO_HWCAP_VAR(s390x_has_ve1) MONO_HWCAP_VAR(s390x_has_vec) MONO_HWCAP_VAR(s390x_has_mlt) MONO_HWCAP_VAR(s390x_has_ia) From 3eab15e6e6be5b07c26614c2aa75779abb841c35 Mon Sep 17 00:00:00 2001 From: Sanjam Panda <36253777+saitama951@users.noreply.github.com> Date: Tue, 5 Aug 2025 14:45:51 +0530 Subject: [PATCH 2/4] Apply suggestions from code review fix code style Co-authored-by: kasperk81 <83082615+kasperk81@users.noreply.github.com> --- src/mono/mono/mini/simd-intrinsics.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index b8f78487cd85e6..0b33399d8634b5 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2183,7 +2183,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; #if defined(TARGET_S390X) if (!mono_hwcap_s390x_has_ve1 && (vector_inner_type == MONO_TYPE_R4)) - return NULL; + return NULL; #endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, vector_inner_type, id); } @@ -2783,7 +2783,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi mono_metadata_type_equal (fsig->params [0], fsig->params [1])); #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) - return NULL; + return NULL; #endif gboolean is_all = FALSE; switch (id) { @@ -4227,7 +4227,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f case SN_Dot: { #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1) - return NULL; + return NULL; #endif return emit_dot (cfg, klass, fsig->params [0], MONO_TYPE_R4, args [0]->dreg, args [1]->dreg); } @@ -4249,7 +4249,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f } #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1) - return NULL; + return NULL; #endif // MAX(x,0-x) MonoInst *zero = emit_xzero (cfg, klass); @@ -4266,7 +4266,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f return NULL; #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1) - return NULL; + return NULL; #endif MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); return emit_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]); @@ -4276,7 +4276,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f return NULL; #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1) - return NULL; + return NULL; #endif MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); return emit_not_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]); @@ -4309,7 +4309,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f #endif #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1) - return NULL; + return NULL; #endif MonoInst *max = emit_simd_ins (cfg, klass, OP_XBINOP, args[0]->dreg, args[1]->dreg); From 0122852025a38503a647967bf148232ce014ab9e Mon Sep 17 00:00:00 2001 From: saitama951 Date: Wed, 6 Aug 2025 04:35:56 +0000 Subject: [PATCH 3/4] fix errors * fix test case failures on arm64 * fix more code style reviews --- src/mono/mono/mini/simd-intrinsics.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 0b33399d8634b5..fab77158e8bdf5 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2782,7 +2782,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi fsig->ret->type == MONO_TYPE_BOOLEAN && mono_metadata_type_equal (fsig->params [0], fsig->params [1])); #ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) + if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4)) return NULL; #endif gboolean is_all = FALSE; @@ -3180,8 +3180,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1 && (id == SN_Negate) && (arg0_type == MONO_TYPE_R4)) - return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id); + return NULL; #endif + return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id); } case SN_Shuffle: { MonoType *etype = get_vector_t_elem_type (fsig->ret); @@ -3849,7 +3850,7 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID; #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1 && ((id !=SN_op_ExclusiveOr) || (id != SN_op_BitwiseAnd) || (id != SN_op_BitwiseOr)) && arg0_type == MONO_TYPE_R4) - return NULL; + return NULL; #endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); @@ -4220,7 +4221,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f #endif #ifdef TARGET_S390X if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative))) - return NULL; + return NULL; #endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, MONO_TYPE_R4, id); } From e96bb2a2aa8e7f48a2e1d1d62e06790a8cbd30d4 Mon Sep 17 00:00:00 2001 From: saitama951 Date: Thu, 14 Aug 2025 12:51:00 +0000 Subject: [PATCH 4/4] address review comments --- src/mono/mono/mini/mini-s390x.h | 2 +- src/mono/mono/mini/mini.h | 11 ++++++++ src/mono/mono/mini/simd-intrinsics.c | 38 +++++++--------------------- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/mono/mono/mini/mini-s390x.h b/src/mono/mono/mini/mini-s390x.h index 6e680ba9c6374b..82b2f411f4d439 100644 --- a/src/mono/mono/mini/mini-s390x.h +++ b/src/mono/mono/mini/mini-s390x.h @@ -83,7 +83,7 @@ struct SeqPointInfo { #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1 #define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1 #define MONO_ARCH_FLOAT32_SUPPORTED 1 -#define MONO_ARCH_SIMD_INTRINSICS mono_hwcap_s390x_has_vec +#define MONO_ARCH_SIMD_INTRINSICS 1 #define MONO_ARCH_NEED_SIMD_BANK 1 #define MONO_ARCH_USE_SHARED_FP_SIMD_BANK 1 #define S390_STACK_ALIGNMENT 8 diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 30e5f5c4728811..65b38b751e8c45 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -64,6 +64,12 @@ typedef struct SeqPointInfo SeqPointInfo; #include "mono/metadata/callspec.h" #include "mono/metadata/icall-signatures.h" +/* we use runtime checks to fallback to scalar ops for/ + * older z/Architectures + */ +#ifdef TARGET_S390X +#include +#endif /* * The mini code should not have any compile time dependencies on the GC being used, so the same object file from mini/ * can be linked into both mono and mono-sgen. @@ -3015,6 +3021,11 @@ mini_safepoints_enabled (void) static inline gboolean mini_class_is_simd (MonoCompile *cfg, MonoClass *klass) { +#ifdef TARGET_S390X + /* vector facility was introduced in z13 */ + if (!mono_hwcap_s390x_has_vec) + return FALSE; +#endif #ifdef MONO_ARCH_SIMD_INTRINSICS if (!(((cfg)->opt & MONO_OPT_SIMD) && m_class_is_simd_type (klass))) return FALSE; diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index fab77158e8bdf5..ebe0637605fe5a 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2138,7 +2138,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; #if defined(TARGET_S390X) - if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative) || (id !=SN_Xor) || (id != SN_BitwiseAnd) || (id != SN_BitwiseOr)) && arg0_type == MONO_TYPE_R4) + if (!mono_hwcap_s390x_has_ve1 && arg0_type == MONO_TYPE_R4) + return NULL; + if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative)) && (arg0_type == MONO_TYPE_R8)) return NULL; #endif @@ -2147,7 +2149,6 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; #endif - return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); } case SN_Divide: { @@ -3849,7 +3850,7 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f return NULL; arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID; #ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1 && ((id !=SN_op_ExclusiveOr) || (id != SN_op_BitwiseAnd) || (id != SN_op_BitwiseOr)) && arg0_type == MONO_TYPE_R4) + if (!mono_hwcap_s390x_has_ve1 && arg0_type == MONO_TYPE_R4) return NULL; #endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); @@ -3968,6 +3969,11 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f return NULL; #endif +#ifdef TARGET_S390X + if (!mono_hwcap_s390x_has_ve1) + return NULL; +#endif + if (!(cfg->opt & MONO_OPT_SIMD)) return NULL; @@ -4218,18 +4224,10 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f #ifndef TARGET_ARM64 if ((id == SN_Max) || (id == SN_Min)) return NULL; -#endif -#ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative))) - return NULL; #endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, MONO_TYPE_R4, id); } case SN_Dot: { -#ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1) - return NULL; -#endif return emit_dot (cfg, klass, fsig->params [0], MONO_TYPE_R4, args [0]->dreg, args [1]->dreg); } case SN_Negate: @@ -4248,10 +4246,6 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f return emit_simd_ins_for_sig (cfg, cmethod->klass, OP_XOP_OVR_X_X, INTRINS_AARCH64_ADV_SIMD_FABS, MONO_TYPE_R4, fsig, args); #endif } -#ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1) - return NULL; -#endif // MAX(x,0-x) MonoInst *zero = emit_xzero (cfg, klass); MonoInst *neg = emit_simd_ins (cfg, klass, OP_XBINOP, zero->dreg, args [0]->dreg); @@ -4265,20 +4259,12 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f case SN_op_Equality: { if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type))) return NULL; -#ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1) - return NULL; -#endif MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); return emit_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]); } case SN_op_Inequality: { if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type))) return NULL; -#ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1) - return NULL; -#endif MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]); return emit_not_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]); } @@ -4290,8 +4276,6 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f ins->inst_c0 = (IntrinsicId)INTRINS_SIMD_SQRT_R4; return ins; #elif defined(TARGET_S390X) - if (!mono_hwcap_s390x_has_ve1) - return NULL; ins = emit_simd_ins (cfg, klass, OP_S390_VFSQSB, args [0]->dreg, -1); return ins; #else @@ -4308,10 +4292,6 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f if (id == SN_Clamp) return NULL; #endif -#ifdef TARGET_S390X - if (!mono_hwcap_s390x_has_ve1) - return NULL; -#endif MonoInst *max = emit_simd_ins (cfg, klass, OP_XBINOP, args[0]->dreg, args[1]->dreg); max->inst_c0 = OP_FMAX;