Skip to content

Commit

Permalink
[Mono] Add intrinsics for several operators (#66317)
Browse files Browse the repository at this point in the history
This PR contributes to  #64072

Added intrinsics for following operators
- Operator *
- Operator /
- Operator |
- Operator &
- Operator ^
- Unary operator -
- Unary operator ~

Co-authored-by: Fan Yang <[email protected]>
  • Loading branch information
mkhamoyan and fanyang-mono authored Mar 10, 2022
1 parent d282630 commit 4a7feea
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 95 deletions.
238 changes: 143 additions & 95 deletions src/mono/mono/mini/simd-intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,115 @@ emit_simd_ins_for_sig (MonoCompile *cfg, MonoClass *klass, int opcode, int instc
return ins;
}

static gboolean type_enum_is_unsigned (MonoTypeEnum type);
static gboolean type_enum_is_float (MonoTypeEnum type);

static MonoInst*
emit_simd_ins_for_binary_op (MonoCompile *cfg, MonoClass *klass, MonoMethodSignature *fsig, MonoInst **args, MonoTypeEnum arg_type, int id)
{
int instc0 = -1;
int op = OP_XBINOP;

if (id == SN_BitwiseAnd || id == SN_BitwiseOr || id == SN_Xor ||
id == SN_op_BitwiseAnd || id == SN_op_BitwiseOr || id == SN_op_ExclusiveOr) {
op = OP_XBINOP_FORCEINT;

switch (id) {
case SN_BitwiseAnd:
case SN_op_BitwiseAnd:
instc0 = XBINOP_FORCEINT_AND;
break;
case SN_BitwiseOr:
case SN_op_BitwiseOr:
instc0 = XBINOP_FORCEINT_OR;
break;
case SN_op_ExclusiveOr:
case SN_Xor:
instc0 = XBINOP_FORCEINT_XOR;
break;
}
} else {
if (type_enum_is_float (arg_type)) {
switch (id) {
case SN_Add:
case SN_op_Addition:
instc0 = OP_FADD;
break;
case SN_Divide:
case SN_op_Division:
instc0 = OP_FDIV;
break;
case SN_Max:
instc0 = OP_FMAX;
break;
case SN_Min:
instc0 = OP_FMIN;
break;
case SN_Multiply:
case SN_op_Multiply:
instc0 = OP_FMUL;
break;
case SN_Subtract:
case SN_op_Subtraction:
instc0 = OP_FSUB;
break;
default:
g_assert_not_reached ();
}
} else {
switch (id) {
case SN_Add:
case SN_op_Addition:
instc0 = OP_IADD;
break;
case SN_Divide:
case SN_op_Division:
return NULL;
case SN_Max:
instc0 = OP_IMAX;
break;
case SN_Min:
instc0 = OP_IMIN;
break;
case SN_Multiply:
case SN_op_Multiply:
instc0 = OP_IMUL;
break;
case SN_Subtract:
case SN_op_Subtraction:
instc0 = OP_ISUB;
break;
default:
g_assert_not_reached ();
}
}
}
return emit_simd_ins_for_sig (cfg, klass, op, instc0, arg_type, fsig, args);
}

static MonoInst*
emit_simd_ins_for_unary_op (MonoCompile *cfg, MonoClass *klass, MonoMethodSignature *fsig, MonoInst **args, MonoTypeEnum arg_type, int id)
{
#ifdef TARGET_ARM64
int op = -1;
switch (id){
case SN_Negate:
case SN_op_UnaryNegation:
op = OP_ARM64_XNEG;
break;
case SN_OnesComplement:
case SN_op_OnesComplement:
op = OP_ARM64_MVN;
break;
default:
g_assert_not_reached ();
}
return emit_simd_ins_for_sig (cfg, klass, op, -1, arg_type, fsig, args);
#else
return NULL;
#endif
}

static gboolean
is_hw_intrinsics_class (MonoClass *klass, const char *name, gboolean *is_64bit)
{
Expand All @@ -285,9 +394,6 @@ get_underlying_type (MonoType* type)
return type->type;
}

static gboolean type_enum_is_unsigned (MonoTypeEnum type);
static gboolean type_enum_is_float (MonoTypeEnum type);

static MonoInst*
emit_xcompare (MonoCompile *cfg, MonoClass *klass, MonoTypeEnum etype, MonoInst *arg1, MonoInst *arg2)
{
Expand Down Expand Up @@ -804,91 +910,25 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
#endif
}
case SN_Add:
case SN_BitwiseAnd:
case SN_BitwiseOr:
case SN_Divide:
case SN_Max:
case SN_Min:
case SN_Multiply:
case SN_Subtract: {
case SN_Subtract:
case SN_Xor:
if (!is_element_type_primitive (fsig->params [0]))
return NULL;
int instc0 = -1;
if (type_enum_is_float (arg0_type)) {
switch (id) {
case SN_Add:
instc0 = OP_FADD;
break;
case SN_Divide:
instc0 = OP_FDIV;
break;
case SN_Max:
instc0 = OP_FMAX;
break;
case SN_Min:
instc0 = OP_FMIN;
break;
case SN_Multiply:
instc0 = OP_FMUL;
break;
case SN_Subtract:
instc0 = OP_FSUB;
break;
default:
g_assert_not_reached ();
}
} else {
switch (id) {
case SN_Add:
instc0 = OP_IADD;
break;
case SN_Divide:
return NULL;
case SN_Max:
instc0 = OP_IMAX;
break;
case SN_Min:
instc0 = OP_IMIN;
break;
case SN_Multiply:
instc0 = OP_IMUL;
break;
case SN_Subtract:
instc0 = OP_ISUB;
break;
default:
g_assert_not_reached ();
}
}
return emit_simd_ins_for_sig (cfg, klass, OP_XBINOP, instc0, arg0_type, fsig, args);
}
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id);
case SN_AndNot:
#ifdef TARGET_ARM64
if (!is_element_type_primitive (fsig->params [0]))
return NULL;
#ifdef TARGET_ARM64
return emit_simd_ins_for_sig (cfg, klass, OP_ARM64_BIC, -1, arg0_type, fsig, args);
#else
return NULL;
#endif
case SN_BitwiseAnd:
case SN_BitwiseOr:
case SN_Xor: {
if (!is_element_type_primitive (fsig->params [0]))
return NULL;
int instc0 = -1;
switch (id) {
case SN_BitwiseAnd:
instc0 = XBINOP_FORCEINT_AND;
break;
case SN_BitwiseOr:
instc0 = XBINOP_FORCEINT_OR;
break;
case SN_Xor:
instc0 = XBINOP_FORCEINT_XOR;
break;
default:
g_assert_not_reached ();
}
return emit_simd_ins_for_sig (cfg, klass, OP_XBINOP_FORCEINT, instc0, arg0_type, fsig, args);
}
case SN_As:
case SN_AsByte:
case SN_AsDouble:
Expand Down Expand Up @@ -916,9 +956,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
#endif
}
case SN_ConditionalSelect: {
#ifdef TARGET_ARM64
if (!is_element_type_primitive (fsig->params [0]))
return NULL;
#ifdef TARGET_ARM64
return emit_simd_ins_for_sig (cfg, klass, OP_ARM64_BSL, -1, arg0_type, fsig, args);
#else
return NULL;
Expand Down Expand Up @@ -1062,17 +1102,12 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
case SN_OnesComplement: {
if (!is_element_type_primitive (fsig->params [0]))
return NULL;
#ifdef TARGET_ARM64
int op = id == SN_Negate ? OP_ARM64_XNEG : OP_ARM64_MVN;
return emit_simd_ins_for_sig (cfg, klass, op, -1, arg0_type, fsig, args);
#else
return NULL;
#endif
return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id);
}
case SN_Sqrt: {
#ifdef TARGET_ARM64
if (!is_element_type_primitive (fsig->params [0]))
return NULL;
#ifdef TARGET_ARM64
if (!type_enum_is_float (arg0_type))
return NULL;
return emit_simd_ins_for_sig (cfg, klass, OP_XOP_OVR_X_X, INTRINS_AARCH64_ADV_SIMD_FSQRT, arg0_type, fsig, args);
Expand Down Expand Up @@ -1130,9 +1165,16 @@ static guint16 vector64_vector128_t_methods [] = {
SN_get_IsSupported,
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_Multiply,
SN_op_OnesComplement,
SN_op_Subtraction,
SN_op_UnaryNegation,
};

static MonoInst*
Expand All @@ -1152,6 +1194,7 @@ emit_vector64_vector128_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
g_assert (size > 0);
g_assert (esize > 0);
int len = size / esize;
MonoTypeEnum arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID;

if (!MONO_TYPE_IS_INTRINSICS_VECTOR_PRIMITIVE (etype))
return NULL;
Expand Down Expand Up @@ -1197,27 +1240,32 @@ emit_vector64_vector128_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
break;
}
case SN_op_Addition:
case SN_op_Subtraction: {
if (!(fsig->param_count == 2 && mono_metadata_type_equal (fsig->ret, type) && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type)))
case SN_op_BitwiseAnd:
case SN_op_BitwiseOr:
case SN_op_Division:
case SN_op_ExclusiveOr:
case SN_op_Multiply:
case SN_op_Subtraction: {
if (fsig->param_count != 2 )
return NULL;
MonoInst *ins = emit_simd_ins (cfg, klass, OP_XBINOP, args [0]->dreg, args [1]->dreg);
ins->inst_c1 = etype->type;
if (etype->type == MONO_TYPE_R4 || etype->type == MONO_TYPE_R8)
ins->inst_c0 = id == SN_op_Addition ? OP_FADD : OP_FSUB;
else
ins->inst_c0 = id == SN_op_Addition ? OP_IADD : OP_ISUB;
return ins;
MonoTypeEnum arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID;
return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id);

}
case SN_op_Equality:
case SN_op_Inequality:
g_assert (fsig->param_count == 2 && fsig->ret->type == MONO_TYPE_BOOLEAN &&
mono_metadata_type_equal (fsig->params [0], type) &&
mono_metadata_type_equal (fsig->params [1], type));
if (fsig->param_count != 2 )
return NULL;
switch (id) {
case SN_op_Equality: return emit_xequal (cfg, klass, args [0], args [1]);
case SN_op_Inequality: return emit_not_xequal (cfg, klass, args [0], args [1]);
default: g_assert_not_reached ();
}
case SN_op_OnesComplement:
case SN_op_UnaryNegation:
if (fsig->param_count != 1 )
return NULL;
return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id);
default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/mini/simd-methods.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ METHOD(op_ExclusiveOr)
METHOD(op_Explicit)
METHOD(op_Inequality)
METHOD(op_Multiply)
METHOD(op_OnesComplement)
METHOD(op_Subtraction)
METHOD(op_UnaryNegation)
// Vector
METHOD(ConvertToInt32)
METHOD(ConvertToInt32WithTruncation)
Expand Down

0 comments on commit 4a7feea

Please sign in to comment.