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 88143637310ef9..ebe0637605fe5a 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,6 +2137,13 @@ 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 && 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 + #if !defined(TARGET_ARM64) && !defined(TARGET_S390X) if (((id == SN_Max) || (id == SN_Min)) && type_enum_is_float(arg0_type)) return NULL; @@ -2149,7 +2158,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 +2182,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 +2213,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 +2293,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 +2485,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 +2497,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 +2762,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 +2782,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 +2892,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 +2918,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 +2949,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 +3030,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,6 +3179,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 NULL; +#endif return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id); } case SN_Shuffle: { @@ -3295,6 +3349,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 +3849,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 && arg0_type == MONO_TYPE_R4) + return NULL; +#endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); } @@ -3800,6 +3861,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 +3875,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) @@ -3900,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; @@ -4201,6 +4275,9 @@ 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) + ins = emit_simd_ins (cfg, klass, OP_S390_VFSQSB, args [0]->dreg, -1); + return ins; #else return NULL; #endif @@ -6865,6 +6942,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)