Skip to content

Commit 96e621b

Browse files
committed
[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.
1 parent 56b2a2a commit 96e621b

File tree

3 files changed

+109
-7
lines changed

3 files changed

+109
-7
lines changed

src/mono/mono/mini/simd-intrinsics.c

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
21122112
}
21132113
#elif defined(TARGET_S390X)
21142114
if (type_enum_is_float(arg0_type)) {
2115+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2116+
return NULL;
21152117
return emit_simd_ins_for_sig (cfg, klass, arg0_type == MONO_TYPE_R8 ? OP_S390_VFLPDB : OP_S390_VFLPSB, -1, arg0_type, fsig, args);
21162118
} else {
21172119
return emit_simd_ins_for_sig (cfg, klass, OP_VECTOR_IABS, -1, arg0_type, fsig, args);
@@ -2135,11 +2137,16 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
21352137
if (!is_element_type_primitive (fsig->params [0]) || !is_element_type_primitive (fsig->params [1]))
21362138
return NULL;
21372139

2138-
#if !defined(TARGET_ARM64) && !defined(TARGET_S390X)
2140+
#if !defined(TARGET_ARM64)
21392141
if (((id == SN_Max) || (id == SN_Min)) && type_enum_is_float(arg0_type))
21402142
return NULL;
21412143
#endif
21422144

2145+
#if defined(TARGET_S390X)
2146+
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)
2147+
return NULL;
2148+
#endif
2149+
21432150
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id);
21442151
}
21452152
case SN_Divide: {
@@ -2149,7 +2156,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
21492156
if (!is_element_type_primitive (fsig->params [0]) ||
21502157
!(MONO_TYPE_IS_VECTOR_PRIMITIVE (fsig->params [1]) || is_element_type_primitive (fsig->params [1])))
21512158
return NULL;
2152-
2159+
#if defined(TARGET_S390X)
2160+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2161+
return NULL;
2162+
#endif
21532163
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id);
21542164
}
21552165
case SN_Multiply: {
@@ -2170,7 +2180,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
21702180
return NULL;
21712181
} else if (!(is_element_type_primitive (fsig->params [0]) && is_element_type_primitive (fsig->params [1])))
21722182
return NULL;
2173-
2183+
#if defined(TARGET_S390X)
2184+
if (!mono_hwcap_s390x_has_ve1 && (vector_inner_type == MONO_TYPE_R4))
2185+
return NULL;
2186+
#endif
21742187
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, vector_inner_type, id);
21752188
}
21762189
case SN_AndNot: {
@@ -2198,13 +2211,17 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
21982211
int add_op;
21992212

22002213
if (type_enum_is_float (arg0_type)) {
2214+
#if defined(TARGET_S390X)
2215+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2216+
return NULL;
2217+
#endif
22012218
mul_op = OP_FMUL;
22022219
add_op = OP_FADD;
22032220
} else {
22042221
mul_op = OP_IMUL;
22052222
add_op = OP_IADD;
22062223

2207-
#ifdef TARGET_ARM64
2224+
#if defined(TARGET_ARM64) || defined(TARGET_S390X)
22082225
if (!COMPILE_LLVM (cfg) && (arg0_type == MONO_TYPE_I8 || arg0_type == MONO_TYPE_U8 || arg0_type == MONO_TYPE_I || arg0_type == MONO_TYPE_U))
22092226
return NULL;
22102227
#endif
@@ -2274,6 +2291,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
22742291
int ceil_or_floor = id == SN_Ceiling ? 10 : 9;
22752292
return emit_simd_ins_for_sig (cfg, klass, OP_SSE41_ROUNDP, ceil_or_floor, arg0_type, fsig, args);
22762293
#elif defined(TARGET_S390X)
2294+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2295+
return NULL;
22772296
int ceil_or_floor = id == SN_Ceiling ? 6 : 7;
22782297
switch (arg0_type){
22792298
case MONO_TYPE_R4:
@@ -2464,6 +2483,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
24642483
return emit_vector_create_scalar (cfg, vklass, etype, args [0], is_unsafe);
24652484
}
24662485
case SN_Dot: {
2486+
#if defined(TARGET_S390X)
2487+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2488+
return NULL;
2489+
#endif
24672490
return emit_dot (cfg, klass, fsig->params [0], arg0_type, args [0]->dreg, args [1]->dreg);
24682491
}
24692492
case SN_Equals:
@@ -2472,6 +2495,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
24722495
if (!is_element_type_primitive (fsig->params [0]))
24732496
return NULL;
24742497
MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]);
2498+
#ifdef TARGET_S390X
2499+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2500+
return NULL;
2501+
#endif
24752502
if (id == SN_Equals)
24762503
return emit_xcompare (cfg, klass, arg0_type, args [0], args [1]);
24772504

@@ -2733,7 +2760,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
27332760
case SN_LessThanOrEqual: {
27342761
if (!is_element_type_primitive (fsig->params [0]))
27352762
return NULL;
2736-
2763+
#ifdef TARGET_S390X
2764+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2765+
return NULL;
2766+
#endif
27372767
return emit_xcompare_for_intrinsic (cfg, klass, id, arg0_type, args [0], args [1]);
27382768
}
27392769
case SN_GreaterThanAll:
@@ -2750,7 +2780,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
27502780
g_assert (fsig->param_count == 2 &&
27512781
fsig->ret->type == MONO_TYPE_BOOLEAN &&
27522782
mono_metadata_type_equal (fsig->params [0], fsig->params [1]));
2753-
2783+
#ifdef TARGET_S390X
2784+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2785+
return NULL;
2786+
#endif
27542787
gboolean is_all = FALSE;
27552788
switch (id) {
27562789
case SN_GreaterThanAll:
@@ -2857,6 +2890,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
28572890
return NULL;
28582891
if (!type_enum_is_float(arg0_type))
28592892
return emit_xzero (cfg, klass);
2893+
#ifdef TARGET_S390X
2894+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2895+
return NULL;
2896+
#endif
28602897
int op = -1;
28612898
#if defined(TARGET_ARM64) || defined(TARGET_AMD64) || defined(TARGET_WASM) || defined(TARGET_S390X)
28622899
op = OP_ONES_COMPLEMENT;
@@ -2879,7 +2916,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
28792916
return emit_xones (cfg, klass);
28802917
}
28812918
}
2882-
2919+
#ifdef TARGET_S390X
2920+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2921+
return NULL;
2922+
#endif
28832923
MonoInst *arg0 = args [0];
28842924
MonoClass *op_klass = klass;
28852925

@@ -2907,6 +2947,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
29072947
case SN_IsPositiveInfinity: {
29082948
if (!is_element_type_primitive (fsig->params [0]))
29092949
return NULL;
2950+
#ifdef TARGET_S390X
2951+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
2952+
return NULL;
2953+
#endif
29102954
if (arg0_type == MONO_TYPE_R4) {
29112955
guint32 value[4];
29122956

@@ -2984,6 +3028,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
29843028
case SN_IsZero: {
29853029
if (!is_element_type_primitive (fsig->params [0]))
29863030
return NULL;
3031+
#ifdef TARGET_S390X
3032+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
3033+
return NULL;
3034+
#endif
29873035
return emit_xcompare (cfg, klass, arg0_type, args [0], emit_xzero (cfg, klass));
29883036
}
29893037
case SN_Narrow: {
@@ -3129,7 +3177,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
31293177
case SN_OnesComplement: {
31303178
if (!is_element_type_primitive (fsig->params [0]))
31313179
return NULL;
3180+
#ifdef TARGET_S390X
3181+
if (!mono_hwcap_s390x_has_ve1 && (id == SN_Negate) && (arg0_type == MONO_TYPE_R4))
31323182
return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id);
3183+
#endif
31333184
}
31343185
case SN_Shuffle: {
31353186
MonoType *etype = get_vector_t_elem_type (fsig->ret);
@@ -3295,6 +3346,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
32953346

32963347
return emit_simd_ins_for_sig (cfg, klass, OP_XOP_X_X, instc0, arg0_type, fsig, args);
32973348
#elif defined(TARGET_S390X)
3349+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
3350+
return NULL;
3351+
32983352
int instc0 = arg0_type == MONO_TYPE_R4 ? OP_S390_VFSQSB : OP_S390_VFSQDB;
32993353
return emit_simd_ins_for_sig (cfg, klass, instc0, 0, arg0_type, fsig, args);
33003354
#else
@@ -3792,6 +3846,10 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
37923846
if (fsig->param_count != 2 )
37933847
return NULL;
37943848
arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID;
3849+
#ifdef TARGET_S390X
3850+
if (!mono_hwcap_s390x_has_ve1 && ((id !=SN_op_ExclusiveOr) || (id != SN_op_BitwiseAnd) || (id != SN_op_BitwiseOr)) && arg0_type == MONO_TYPE_R4)
3851+
return NULL;
3852+
#endif
37953853
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id);
37963854

37973855
}
@@ -3800,6 +3858,10 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
38003858
if (fsig->param_count != 2 )
38013859
return NULL;
38023860
MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]);
3861+
#ifdef TARGET_S390X
3862+
if (!mono_hwcap_s390x_has_ve1 && (arg0_type == MONO_TYPE_R4))
3863+
return NULL;
3864+
#endif
38033865
switch (id) {
38043866
case SN_op_Equality: return emit_xequal (cfg, arg_class, arg0_type, args [0], args [1]);
38053867
case SN_op_Inequality: return emit_not_xequal (cfg, arg_class, arg0_type, args [0], args [1]);
@@ -3810,6 +3872,10 @@ emit_sri_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
38103872
case SN_op_UnaryNegation:
38113873
if (fsig->param_count != 1 )
38123874
return NULL;
3875+
#if defined(TARGET_S390X)
3876+
if (!mono_hwcap_s390x_has_ve1 && (id == SN_op_UnaryNegation) && (arg0_type == MONO_TYPE_R4))
3877+
return NULL;
3878+
#endif
38133879
return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id);
38143880
case SN_op_UnaryPlus:
38153881
if (fsig->param_count != 1)
@@ -4150,10 +4216,18 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
41504216
#ifndef TARGET_ARM64
41514217
if ((id == SN_Max) || (id == SN_Min))
41524218
return NULL;
4219+
#endif
4220+
#ifdef TARGET_S390X
4221+
if (!mono_hwcap_s390x_has_ve1 && ((id == SN_Max) || (id == SN_Min) || (id == SN_MaxNative) || (id == SN_MinNative)))
4222+
return NULL;
41534223
#endif
41544224
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, MONO_TYPE_R4, id);
41554225
}
41564226
case SN_Dot: {
4227+
#ifdef TARGET_S390X
4228+
if (!mono_hwcap_s390x_has_ve1)
4229+
return NULL;
4230+
#endif
41574231
return emit_dot (cfg, klass, fsig->params [0], MONO_TYPE_R4, args [0]->dreg, args [1]->dreg);
41584232
}
41594233
case SN_Negate:
@@ -4172,6 +4246,10 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
41724246
return emit_simd_ins_for_sig (cfg, cmethod->klass, OP_XOP_OVR_X_X, INTRINS_AARCH64_ADV_SIMD_FABS, MONO_TYPE_R4, fsig, args);
41734247
#endif
41744248
}
4249+
#ifdef TARGET_S390X
4250+
if (!mono_hwcap_s390x_has_ve1)
4251+
return NULL;
4252+
#endif
41754253
// MAX(x,0-x)
41764254
MonoInst *zero = emit_xzero (cfg, klass);
41774255
MonoInst *neg = emit_simd_ins (cfg, klass, OP_XBINOP, zero->dreg, args [0]->dreg);
@@ -4185,12 +4263,20 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
41854263
case SN_op_Equality: {
41864264
if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type)))
41874265
return NULL;
4266+
#ifdef TARGET_S390X
4267+
if (!mono_hwcap_s390x_has_ve1)
4268+
return NULL;
4269+
#endif
41884270
MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]);
41894271
return emit_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]);
41904272
}
41914273
case SN_op_Inequality: {
41924274
if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type)))
41934275
return NULL;
4276+
#ifdef TARGET_S390X
4277+
if (!mono_hwcap_s390x_has_ve1)
4278+
return NULL;
4279+
#endif
41944280
MonoClass *arg_class = mono_class_from_mono_type_internal (fsig->params [0]);
41954281
return emit_not_xequal (cfg, arg_class, MONO_TYPE_R4, args [0], args [1]);
41964282
}
@@ -4201,6 +4287,11 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
42014287
ins = emit_simd_ins (cfg, klass, OP_XOP_X_X, args [0]->dreg, -1);
42024288
ins->inst_c0 = (IntrinsicId)INTRINS_SIMD_SQRT_R4;
42034289
return ins;
4290+
#elif defined(TARGET_S390X)
4291+
if (!mono_hwcap_s390x_has_ve1)
4292+
return NULL;
4293+
ins = emit_simd_ins (cfg, klass, OP_S390_VFSQSB, args [0]->dreg, -1);
4294+
return ins;
42044295
#else
42054296
return NULL;
42064297
#endif
@@ -4215,6 +4306,10 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f
42154306
if (id == SN_Clamp)
42164307
return NULL;
42174308
#endif
4309+
#ifdef TARGET_S390X
4310+
if (!mono_hwcap_s390x_has_ve1)
4311+
return NULL;
4312+
#endif
42184313

42194314
MonoInst *max = emit_simd_ins (cfg, klass, OP_XBINOP, args[0]->dreg, args[1]->dreg);
42204315
max->inst_c0 = OP_FMAX;
@@ -6865,6 +6960,11 @@ static MonoInst*
68656960
emit_simd_intrinsics (const char *class_ns, const char *class_name, MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
68666961
{
68676962
MonoInst *ins;
6963+
#ifdef TARGET_S390X
6964+
/* vector facility was introduced in z13 */
6965+
if (!mono_hwcap_s390x_has_vec)
6966+
return NULL;
6967+
#endif
68686968

68696969
if (cfg->opt & MONO_OPT_SIMD) {
68706970
ins = arch_emit_simd_intrinsics (class_ns, class_name, cfg, cmethod, fsig, args);

src/mono/mono/utils/mono-hwcap-s390x.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ mono_hwcap_arch_init (void)
157157

158158
mono_hwcap_s390x_has_fpe = facs.fpe;
159159
mono_hwcap_s390x_has_vec = facs.vec;
160+
mono_hwcap_s390x_has_ve1 = facs.ve1;
160161
mono_hwcap_s390x_has_mlt = facs.multi;
161162
mono_hwcap_s390x_has_ia = facs.ia;
162163
mono_hwcap_s390x_has_gie = facs.gie;

src/mono/mono/utils/mono-hwcap-vars.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ MONO_HWCAP_VAR(riscv_has_stdext_v)
5454
#elif defined (TARGET_S390X)
5555

5656
MONO_HWCAP_VAR(s390x_has_fpe)
57+
MONO_HWCAP_VAR(s390x_has_ve1)
5758
MONO_HWCAP_VAR(s390x_has_vec)
5859
MONO_HWCAP_VAR(s390x_has_mlt)
5960
MONO_HWCAP_VAR(s390x_has_ia)

0 commit comments

Comments
 (0)