[jit] Add a netcore version of simd-intrinsics.c.
authorZoltan Varga <vargaz@gmail.com>
Fri, 16 Aug 2019 08:09:50 +0000 (04:09 -0400)
committerZoltan Varga <vargaz@gmail.com>
Sat, 17 Aug 2019 16:25:30 +0000 (12:25 -0400)
Differences from the old versions:
- Only Vector<T> from corelib is supported.
- Only LLVM is supported.
- It uses more general opcodes like XBINOP instead of having one opcode
  for every op+type combination which is not useful for LLVM.

Commit migrated from https://github.com/mono/mono/commit/98a02059e8753b30d36517805279b5caa308241b

src/mono/mono/metadata/class-init.c
src/mono/mono/mini/Makefile.am.in
src/mono/mono/mini/mini-llvm.c
src/mono/mono/mini/mini-ops.h
src/mono/mono/mini/simd-intrinsics-netcore.c [new file with mode: 0644]
src/mono/mono/mini/simd-intrinsics.c
src/mono/mono/mini/simd-methods-netcore.h [new file with mode: 0644]

index 248be0b..de63685 100644 (file)
@@ -796,6 +796,14 @@ mono_class_create_generic_inst (MonoGenericClass *gclass)
                if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
                        klass->simd_type = 1;
        }
+#ifdef ENABLE_NETCORE
+       if (mono_is_corlib_image (gklass->image) && !strcmp (gklass->name, "Vector`1")) {
+               MonoType *etype = gclass->context.class_inst->type_argv [0];
+               if (mono_type_is_primitive (etype) && etype->type != MONO_TYPE_CHAR && etype->type != MONO_TYPE_BOOLEAN)
+                       klass->simd_type = 1;
+       }
+#endif
+
        klass->is_array_special_interface = gklass->is_array_special_interface;
 
        klass->cast_class = klass->element_class = klass;
index d6ec818..8602157 100755 (executable)
@@ -483,9 +483,11 @@ common_sources = \
        branch-opts.c           \
        mini-generic-sharing.c  \
        simd-methods.h          \
+       simd-methods-netcore.h  \
        tasklets.c              \
        tasklets.h              \
        simd-intrinsics.c       \
+       simd-intrinsics-netcore.c       \
        mini-native-types.c \
        mini-unwind.h           \
        unwind.c                \
index a969a3b..0dfd927 100644 (file)
@@ -1294,7 +1294,9 @@ convert_full (EmitContext *ctx, LLVMValueRef v, LLVMTypeRef dtype, gboolean is_u
                        return LLVMBuildBitCast (ctx->builder, v, dtype, "");
 
                LLVMDumpValue (v);
+               printf ("\n");
                LLVMDumpValue (LLVMConstNull (dtype));
+               printf ("\n");
                g_assert_not_reached ();
                return NULL;
        } else {
@@ -7078,6 +7080,97 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        break;
                }
 
+               case OP_XCOMPARE_FP: {
+                       LLVMRealPredicate pred = fpcond_to_llvm_cond [ins->inst_c0];
+                       LLVMValueRef cmp = LLVMBuildFCmp (builder, pred, lhs, rhs, "");
+                       if (LLVMGetVectorSize (LLVMTypeOf (lhs)) == 2)
+                               values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt64Type (), 2), ""), LLVMTypeOf (lhs), "");
+                       else
+                               values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt32Type (), 4), ""), LLVMTypeOf (lhs), "");
+                       break;
+               }
+               case OP_XCOMPARE: {
+                       LLVMIntPredicate pred = cond_to_llvm_cond [ins->inst_c0];
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, pred, lhs, rhs, "");
+                       values [ins->dreg] = LLVMBuildSExt (builder, cmp, LLVMTypeOf (lhs), "");
+                       break;
+               }
+               case OP_XEQUAL: {
+                       LLVMTypeRef t = LLVMVectorType (LLVMInt8Type (), 16);
+                       LLVMValueRef mask [16], shuffle;
+
+                       //%c = icmp sgt <16 x i8> %a0, %a1
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntEQ, lhs, rhs, "");
+                       cmp = LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt8Type (), 16), "");
+                       // cmp is a <16 x i8> vector, each element is either 0xff or 0
+                       // AND [0..7] and [8..15] into [0..7]
+                       for (int i = 0; i < 8; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 8 + i, FALSE);
+                       for (int i = 8; i < 16; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+                       shuffle = LLVMBuildShuffleVector (builder, cmp, LLVMGetUndef (t), LLVMConstVector (mask, LLVMGetVectorSize (t)), "");
+                       cmp = LLVMBuildAnd (builder, cmp, shuffle, "");
+                       // AND [0..3] and [4..7] into [0..3]
+                       for (int i = 0; i < 4; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 4 + i, FALSE);
+                       for (int i = 4; i < 16; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+                       shuffle = LLVMBuildShuffleVector (builder, cmp, LLVMGetUndef (t), LLVMConstVector (mask, LLVMGetVectorSize (t)), "");
+                       cmp = LLVMBuildAnd (builder, cmp, shuffle, "");
+                       // AND [0..1] and [2..3] into [0..1]
+                       for (int i = 0; i < 2; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 2 + i, FALSE);
+                       for (int i = 2; i < 16; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+                       shuffle = LLVMBuildShuffleVector (builder, cmp, LLVMGetUndef (t), LLVMConstVector (mask, LLVMGetVectorSize (t)), "");
+                       cmp = LLVMBuildAnd (builder, cmp, shuffle, "");
+                       // AND [0] and [1] into [0]
+                       for (int i = 0; i < 1; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 1 + i, FALSE);
+                       for (int i = 1; i < 16; ++i)
+                               mask [i] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+                       shuffle = LLVMBuildShuffleVector (builder, cmp, LLVMGetUndef (t), LLVMConstVector (mask, LLVMGetVectorSize (t)), "");
+                       cmp = LLVMBuildAnd (builder, cmp, shuffle, "");
+                       // Extract [0]
+                       values [ins->dreg] = LLVMBuildExtractElement (builder, cmp, LLVMConstInt (LLVMInt32Type (), 0, FALSE), "");
+                       // Maybe convert to 0/1 ?
+                       break;
+               }
+
+               case OP_XBINOP: {
+                       switch (ins->inst_c0) {
+                       case OP_IADD:
+                               values [ins->dreg] = LLVMBuildAdd (builder, lhs, rhs, "");
+                               break;
+                       case OP_ISUB:
+                               values [ins->dreg] = LLVMBuildSub (builder, lhs, rhs, "");
+                               break;
+                       case OP_IAND:
+                               values [ins->dreg] = LLVMBuildAnd (builder, lhs, rhs, "");
+                               break;
+                       case OP_IOR:
+                               values [ins->dreg] = LLVMBuildOr (builder, lhs, rhs, "");
+                               break;
+                       case OP_IXOR:
+                               values [ins->dreg] = LLVMBuildXor (builder, lhs, rhs, "");
+                               break;
+                       case OP_FADD:
+                               values [ins->dreg] = LLVMBuildFAdd (builder, lhs, rhs, "");
+                               break;
+                       case OP_FSUB:
+                               values [ins->dreg] = LLVMBuildFSub (builder, lhs, rhs, "");
+                               break;
+                       case OP_FMUL:
+                               values [ins->dreg] = LLVMBuildFMul (builder, lhs, rhs, "");
+                               break;
+                       case OP_FDIV:
+                               values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, "");
+                               break;
+                       default:
+                               g_assert_not_reached ();
+                       }
+                       break;
+               }
 #endif /* SIMD */
 
                case OP_DUMMY_USE:
index 339f72f..5992595 100644 (file)
@@ -1354,3 +1354,11 @@ MINI_OP(OP_GET_LAST_ERROR, "get_last_error", IREG, NONE, NONE)
  * should be enough to locate arguments and variables.
  */
 MINI_OP(OP_FILL_PROF_CALL_CTX, "fill_prof_call_ctx", NONE, IREG, NONE)
+
+/* LLVM only, compare 2 vectors for equality, set dreg to 1/0 */
+MINI_OP(OP_XEQUAL, "xequal", IREG, XREG, XREG)
+/* Per element compate, inst_c0 contains a CompRelation */
+MINI_OP(OP_XCOMPARE, "xcompare", XREG, XREG, XREG)
+MINI_OP(OP_XCOMPARE_FP, "xcompare_fp", XREG, XREG, XREG)
+/* Binary op, inst_c0 contains the operation */
+MINI_OP(OP_XBINOP, "xbinop", XREG, XREG, XREG)
diff --git a/src/mono/mono/mini/simd-intrinsics-netcore.c b/src/mono/mono/mini/simd-intrinsics-netcore.c
new file mode 100644 (file)
index 0000000..d82d345
--- /dev/null
@@ -0,0 +1,438 @@
+/**
+ * SIMD Intrinsics support for netcore
+ */
+
+#include <config.h>
+
+/*
+ * On LLVM is supported as a backend.
+ */
+
+#if !defined(DISABLE_JIT) && defined(ENABLE_NETCORE)
+
+#include "mini.h"
+#include "ir-emit.h"
+#include "mono/utils/bsearch.h"
+#include <mono/metadata/abi-details.h>
+#include <mono/metadata/reflection-internals.h>
+
+#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
+#define MSGSTRFIELD1(line) str##line
+static const struct msgstr_t {
+#define SIMD_METHOD(str,name) char MSGSTRFIELD(__LINE__) [sizeof (str)];
+#include "simd-methods-netcore.h"
+#undef SIMD_METHOD
+} method_names = {
+#define SIMD_METHOD(str,name) str,
+#include "simd-methods-netcore.h"
+#undef SIMD_METHOD
+};
+
+enum {
+#define SIMD_METHOD(str,name) name = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
+#include "simd-methods-netcore.h"
+};
+#define method_name(idx) ((const char*)&method_names + (idx))
+
+void
+mono_simd_intrinsics_init (void)
+{
+}
+
+MonoInst*
+mono_emit_simd_field_load (MonoCompile *cfg, MonoClassField *field, MonoInst *addr)
+{
+       return NULL;
+}
+
+static int
+simd_intrinsic_compare_by_name (const void *key, const void *value)
+{
+       return strcmp ((const char*)key, method_name (*(guint16*)value));
+}
+
+static int
+lookup_intrins (guint16 *intrinsics, int size, MonoMethod *cmethod)
+{
+       const guint16 *result = (const guint16 *)mono_binary_search (cmethod->name, intrinsics, size / sizeof (guint16), sizeof (guint16), &simd_intrinsic_compare_by_name);
+
+       for (int i = 0; i < (size / sizeof (guint16)) - 1; ++i) {
+               if (method_name (intrinsics [i])[0] > method_name (intrinsics [i + 1])[0]) {
+                       printf ("%s %s\n",method_name (intrinsics [i]), method_name (intrinsics [i + 1]));
+                       g_assert_not_reached ();
+               }
+       }
+
+       if (result == NULL)
+               return -1;
+       else
+               return (int)*result;
+}
+
+static guint16 vector_methods [] = {
+       SN_get_IsHardwareAccelerated
+};
+
+static MonoInst*
+emit_sys_numerics_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+       MonoInst *ins;
+       gboolean supported = FALSE;
+       int id;
+
+       id = lookup_intrins (vector_methods, sizeof (vector_methods), cmethod);
+       if (id == -1)
+               return NULL;
+
+       //printf ("%s\n", mono_method_full_name (cmethod, 1));
+
+#ifdef MONO_ARCH_SIMD_INTRINSICS
+       supported = TRUE;
+#endif
+
+       switch (id) {
+       case SN_get_IsHardwareAccelerated:
+               EMIT_NEW_ICONST (cfg, ins, supported ? 1 : 0);
+               ins->type = STACK_I4;
+               return ins;
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+static int
+type_to_expand_op (MonoType *type)
+{
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+               return OP_EXPAND_I1;
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+               return OP_EXPAND_I2;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+               return OP_EXPAND_I4;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               return OP_EXPAND_I8;
+       case MONO_TYPE_R4:
+               return OP_EXPAND_R4;
+       case MONO_TYPE_R8:
+               return OP_EXPAND_R8;
+       default:
+               g_assert_not_reached ();
+       }
+}
+
+/*
+ * Return a simd vreg for the simd value represented by SRC.
+ * SRC is the 'this' argument to methods.
+ * Set INDIRECT to TRUE if the value was loaded from memory.
+ */
+static int
+load_simd_vreg_class (MonoCompile *cfg, MonoClass *klass, MonoInst *src, gboolean *indirect)
+{
+       const char *spec = INS_INFO (src->opcode);
+
+       if (indirect)
+               *indirect = FALSE;
+       if (src->opcode == OP_XMOVE) {
+               return src->sreg1;
+       } else if (src->opcode == OP_LDADDR) {
+               int res = ((MonoInst*)src->inst_p0)->dreg;
+               return res;
+       } else if (spec [MONO_INST_DEST] == 'x') {
+               return src->dreg;
+       } else if (src->type == STACK_PTR || src->type == STACK_MP) {
+               MonoInst *ins;
+               if (indirect)
+                       *indirect = TRUE;
+
+               MONO_INST_NEW (cfg, ins, OP_LOADX_MEMBASE);
+               ins->klass = klass;
+               ins->sreg1 = src->dreg;
+               ins->type = STACK_VTYPE;
+               ins->dreg = alloc_ireg (cfg);
+               MONO_ADD_INS (cfg->cbb, ins);
+               return ins->dreg;
+       }
+       g_warning ("load_simd_vreg:: could not infer source simd (%d) vreg for op", src->type);
+       mono_print_ins (src);
+       g_assert_not_reached ();
+}
+
+static int
+load_simd_vreg (MonoCompile *cfg, MonoMethod *cmethod, MonoInst *src, gboolean *indirect)
+{
+       return load_simd_vreg_class (cfg, cmethod->klass, src, indirect);
+}
+
+/* Create and emit a SIMD instruction, dreg is auto-allocated */
+static MonoInst*
+emit_simd_ins (MonoCompile *cfg, MonoClass *klass, int opcode, int sreg1, int sreg2)
+{
+       const char *spec = INS_INFO (opcode);
+       MonoInst *ins;
+
+       MONO_INST_NEW (cfg, ins, opcode);
+       if (spec [MONO_INST_DEST] == 'x') {
+               ins->dreg = alloc_xreg (cfg);
+               ins->type = STACK_VTYPE;
+       } else if (spec [MONO_INST_DEST] == 'i') {
+               ins->dreg = alloc_ireg (cfg);
+               ins->type = STACK_I4;
+       } else {
+               g_assert_not_reached ();
+       }
+       ins->sreg1 = sreg1;
+       ins->sreg2 = sreg2;
+       ins->klass = klass;
+       MONO_ADD_INS (cfg->cbb, ins);
+       return ins;
+}
+
+static MonoInst*
+emit_xcompare (MonoCompile *cfg, MonoClass *klass, MonoType *etype, MonoInst *arg1, MonoInst *arg2)
+{
+       MonoInst *ins;
+       gboolean is_fp = etype->type == MONO_TYPE_R4 || etype->type == MONO_TYPE_R8;
+
+       ins = emit_simd_ins (cfg, klass, is_fp ? OP_XCOMPARE_FP : OP_XCOMPARE, arg1->dreg, arg2->dreg);
+       ins->inst_c0 = CMP_EQ;
+       return ins;
+}
+
+static guint16 vector_t_methods [] = {
+       SN_ctor,
+       SN_Equals,
+       SN_GreaterThan,
+       SN_LessThan,
+       SN_get_AllOnes,
+       SN_get_Count,
+       SN_get_Item,
+       SN_get_Zero,
+       SN_op_Addition,
+       SN_op_BitwiseAnd,
+       SN_op_BitwiseOr,
+       SN_op_Division,
+       SN_op_Equality,
+       SN_op_ExclusiveOr,
+       SN_op_Explicit,
+       SN_op_Inequality,
+       SN_op_Multiply,
+       SN_op_Subtraction
+};
+
+static MonoInst*
+emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+       MonoInst *ins;
+       MonoType *type, *etype;
+       MonoClass *klass;
+       int size, len, id, index;
+       gboolean is_unsigned;
+
+       id = lookup_intrins (vector_t_methods, sizeof (vector_t_methods), cmethod);
+       if (id == -1)
+               return NULL;
+
+       klass = cmethod->klass;
+       type = m_class_get_byval_arg (klass);
+       etype = mono_class_get_context (klass)->class_inst->type_argv [0];
+       size = mono_class_value_size (mono_class_from_mono_type_internal (etype), NULL);
+       g_assert (size);
+       len = 16 / size;
+
+       if (!MONO_TYPE_IS_PRIMITIVE (etype) || etype->type == MONO_TYPE_CHAR || etype->type == MONO_TYPE_BOOLEAN)
+               return NULL;
+
+       if (cfg->verbose_level > 1) {
+               char *name = mono_method_full_name (cmethod, TRUE);
+               printf ("  SIMD intrinsic %s\n", name);
+               g_free (name);
+       }
+
+       switch (id) {
+       case SN_get_Count:
+               if (!(fsig->param_count == 0 && fsig->ret->type == MONO_TYPE_I4))
+                       break;
+               EMIT_NEW_ICONST (cfg, ins, len);
+               return ins;
+       case SN_get_Zero:
+               g_assert (fsig->param_count == 0 && mono_metadata_type_equal (fsig->ret, type));
+               return emit_simd_ins (cfg, klass, OP_XZERO, -1, -1);
+       case SN_get_AllOnes: {
+               /* Compare a zero vector with itself */
+               ins = emit_simd_ins (cfg, klass, OP_XZERO, -1, -1);
+               return emit_xcompare (cfg, klass, etype, ins, ins);
+       }
+       case SN_get_Item:
+               if (args [1]->opcode != OP_ICONST)
+                       return NULL;
+               index = args [1]->inst_c0;
+               if (index < 0 || index >= len)
+                       return NULL;
+               return NULL;
+       case SN_ctor:
+               if (fsig->param_count == 1 && mono_metadata_type_equal (fsig->params [0], etype)) {
+                       int dreg = load_simd_vreg (cfg, cmethod, args [0], NULL);
+
+                       int opcode = type_to_expand_op (etype);
+                       ins = emit_simd_ins (cfg, klass, opcode, args [1]->dreg, -1);
+                       ins->dreg = dreg;
+                       return ins;
+               }
+               break;
+       case SN_Equals:
+               if (fsig->param_count == 1 && fsig->ret->type == MONO_TYPE_BOOLEAN && mono_metadata_type_equal (fsig->params [0], type)) {
+                       int sreg1 = load_simd_vreg (cfg, cmethod, args [0], NULL);
+
+                       return emit_simd_ins (cfg, klass, OP_XEQUAL, sreg1, args [1]->dreg);
+               } else 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)) {
+                       /* Per element equality */
+                       return emit_xcompare (cfg, klass, etype, args [0], args [1]);
+               }
+               break;
+       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));
+               ins = emit_simd_ins (cfg, klass, OP_XEQUAL, args [0]->dreg, args [1]->dreg);
+               if (id == SN_op_Inequality) {
+                       int sreg = ins->dreg;
+                       int dreg = alloc_ireg (cfg);
+                       EMIT_NEW_UNALU (cfg, ins, OP_INOT, dreg, sreg);
+               }
+               return ins;
+       case SN_GreaterThan:
+       case SN_LessThan:
+               g_assert (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));
+               is_unsigned = etype->type == MONO_TYPE_U1 || etype->type == MONO_TYPE_U2 || etype->type == MONO_TYPE_U4 || etype->type == MONO_TYPE_U8;
+               ins = emit_xcompare (cfg, klass, etype, args [0], args [1]);
+               switch (id) {
+               case SN_GreaterThan:
+                       ins->inst_c0 = is_unsigned ? CMP_GT_UN : CMP_GT;
+                       break;
+               case SN_LessThan:
+                       ins->inst_c0 = is_unsigned ? CMP_LT_UN : CMP_LT;
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+               return ins;
+       case SN_op_Explicit:
+               return emit_simd_ins (cfg, klass, OP_XMOVE, args [0]->dreg, -1);
+       case SN_op_Addition:
+       case SN_op_Subtraction:
+       case SN_op_Division:
+       case SN_op_Multiply:
+       case SN_op_BitwiseAnd:
+       case SN_op_BitwiseOr:
+       case SN_op_ExclusiveOr:
+               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)))
+                       return NULL;
+               ins = emit_simd_ins (cfg, klass, OP_XBINOP, args [0]->dreg, args [1]->dreg);
+               if (etype->type == MONO_TYPE_R4 || etype->type == MONO_TYPE_R8) {
+                       switch (id) {
+                       case SN_op_Addition:
+                               ins->inst_c0 = OP_FADD;
+                               break;
+                       case SN_op_Subtraction:
+                               ins->inst_c0 = OP_FSUB;
+                               break;
+                       case SN_op_Multiply:
+                               ins->inst_c0 = OP_FMUL;
+                               break;
+                       case SN_op_Division:
+                               ins->inst_c0 = OP_FDIV;
+                               break;
+                       default:
+                               NULLIFY_INS (ins);
+                               return NULL;
+                       }
+               } else {
+                       switch (id) {
+                       case SN_op_Addition:
+                               ins->inst_c0 = OP_IADD;
+                               break;
+                       case SN_op_Subtraction:
+                               ins->inst_c0 = OP_ISUB;
+                               break;
+                               /*
+                       case SN_op_Division:
+                               ins->inst_c0 = OP_IDIV;
+                               break;
+                       case SN_op_Multiply:
+                               ins->inst_c0 = OP_IMUL;
+                               break;
+                               */
+                       case SN_op_BitwiseAnd:
+                               ins->inst_c0 = OP_IAND;
+                               break;
+                       case SN_op_BitwiseOr:
+                               ins->inst_c0 = OP_IOR;
+                               break;
+                       case SN_op_ExclusiveOr:
+                               ins->inst_c0 = OP_IXOR;
+                               break;
+                       default:
+                               NULLIFY_INS (ins);
+                               return NULL;
+                       }
+               }
+               return ins;
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+MonoInst*
+mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+       const char *class_name;
+       const char *class_ns;
+       MonoImage *image = m_class_get_image (cmethod->klass);
+
+       if (image != mono_get_corlib ())
+               return NULL;
+       if (!COMPILE_LLVM (cfg))
+               return NULL;
+       // FIXME:
+       if (cfg->compile_aot)
+               return NULL;
+       class_ns = m_class_get_name_space (cmethod->klass);
+       class_name = m_class_get_name (cmethod->klass);
+       if (!strcmp (class_ns, "System.Numerics") && !strcmp (class_name, "Vector"))
+               return emit_sys_numerics_vector (cfg, cmethod, fsig, args);
+       if (!strcmp (class_ns, "System.Numerics") && !strcmp (class_name, "Vector`1")) {
+               MonoInst *ins = emit_sys_numerics_vector_t (cfg, cmethod, fsig, args);
+               if (!ins) {
+                       //printf ("M: %s %s\n", mono_method_get_full_name (cfg->method), mono_method_get_full_name (cmethod));
+               }
+               return ins;
+       }
+
+       return NULL;
+}
+
+void
+mono_simd_decompose_intrinsic (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
+{
+}
+
+void
+mono_simd_simplify_indirection (MonoCompile *cfg)
+{
+}
+
+#else
+
+MONO_EMPTY_SOURCE_FILE (simd_intrinsics_netcore);
+
+#endif
index dbfb5a9..c67b165 100644 (file)
 
 #include "mini.h"
 #include "ir-emit.h"
-#include "mono/utils/bsearch.h"
 #include <mono/metadata/abi-details.h>
 #include <mono/metadata/reflection-internals.h>
+#include <mono/utils/mono-compiler.h>
+#include <mono/utils/bsearch.h>
 
 /*
 General notes on SIMD intrinsics
@@ -63,7 +64,7 @@ The advantage of this change is that it could have a _membase version and promot
 without a OP_LDADDR.
 */
 
-#if defined (MONO_ARCH_SIMD_INTRINSICS)
+#if defined (MONO_ARCH_SIMD_INTRINSICS) && !defined(ENABLE_NETCORE)
 
 #if defined (DISABLE_JIT)
 
diff --git a/src/mono/mono/mini/simd-methods-netcore.h b/src/mono/mono/mini/simd-methods-netcore.h
new file mode 100644 (file)
index 0000000..f1a98a9
--- /dev/null
@@ -0,0 +1,22 @@
+SIMD_METHOD(".ctor", SN_ctor)
+SIMD_METHOD("Equals", SN_Equals)
+SIMD_METHOD("GreaterThan", SN_GreaterThan)
+SIMD_METHOD("LessThan", SN_LessThan)
+SIMD_METHOD("Min", SN_Min)
+SIMD_METHOD("Max", SN_Max)
+SIMD_METHOD("get_Count", SN_get_Count)
+SIMD_METHOD("get_IsHardwareAccelerated", SN_get_IsHardwareAccelerated)
+SIMD_METHOD("get_AllOnes", SN_get_AllOnes)
+SIMD_METHOD("get_Item", SN_get_Item)
+SIMD_METHOD("get_One", SN_get_One)
+SIMD_METHOD("get_Zero", SN_get_Zero)
+SIMD_METHOD("op_Addition", SN_op_Addition)
+SIMD_METHOD("op_BitwiseAnd", SN_op_BitwiseAnd)
+SIMD_METHOD("op_BitwiseOr", SN_op_BitwiseOr)
+SIMD_METHOD("op_Division", SN_op_Division)
+SIMD_METHOD("op_Equality", SN_op_Equality)
+SIMD_METHOD("op_ExclusiveOr", SN_op_ExclusiveOr)
+SIMD_METHOD("op_Explicit", SN_op_Explicit)
+SIMD_METHOD("op_Inequality", SN_op_Inequality)
+SIMD_METHOD("op_Multiply", SN_op_Multiply)
+SIMD_METHOD("op_Subtraction", SN_op_Subtraction)