From f04a43fc325e8800743b6324200e2a78ef0c391a Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Tue, 3 Sep 2019 08:31:16 -0400 Subject: [PATCH] [llvm] Implement more SIMD intrinsics on netcore. (mono/mono#16449) * [netcore] Add intrinsics for Vector128/Vector256.Count. * [netcore] Implement Vector.get_Item () as an intrinsic. Commit migrated from https://github.com/mono/mono/commit/98a4d5ec1eb2becf1d002a5fbb070f1079bc6fe4 --- src/mono/mono/mini/mini-codegen.c | 1 + src/mono/mono/mini/mini-llvm.c | 28 +++++++ src/mono/mono/mini/mini-ops.h | 4 + src/mono/mono/mini/simd-intrinsics-netcore.c | 116 +++++++++++++++++++++++++-- 4 files changed, 143 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/mini-codegen.c b/src/mono/mono/mini/mini-codegen.c index a137a70..7d0d99c 100644 --- a/src/mono/mono/mini/mini-codegen.c +++ b/src/mono/mono/mini/mini-codegen.c @@ -2415,6 +2415,7 @@ mono_opcode_to_cond (int opcode) case OP_IBGE_UN: case OP_LBGE_UN: case OP_FBGE_UN: + case OP_COND_EXC_GE_UN: case OP_CMOV_IGE_UN: case OP_CMOV_LGE_UN: return CMP_GE_UN; diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 36d69ce..227e3e8 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -7303,6 +7303,34 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) } break; } + case OP_XEXTRACT_I32: + case OP_XEXTRACT_I64: { + LLVMBasicBlockRef bbs [64]; + LLVMValueRef switch_ins; + LLVMValueRef phi_values [64]; + int nelems = LLVMGetVectorSize (LLVMTypeOf (lhs)); + int i; + + g_assert (nelems <= 64); + for (i = 0; i < nelems; ++i) + bbs [i] = gen_bb (ctx, "XEXTRACT_CASE_BB"); + cbb = gen_bb (ctx, "XEXTRACT_COND_BB"); + + switch_ins = LLVMBuildSwitch (builder, rhs, bbs [0], 0); + for (i = 0; i < nelems; ++i) { + LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i, FALSE), bbs [i]); + LLVMPositionBuilderAtEnd (builder, bbs [i]); + phi_values [i] = LLVMBuildExtractElement (builder, lhs, LLVMConstInt (LLVMInt32Type (), i, FALSE), ""); + LLVMBuildBr (builder, cbb); + } + + LLVMPositionBuilderAtEnd (builder, cbb); + values [ins->dreg] = LLVMBuildPhi (builder, LLVMTypeOf (phi_values [0]), ""); + LLVMAddIncoming (values [ins->dreg], phi_values, bbs, nelems); + + ctx->bblocks [bb->block_num].end_bblock = cbb; + break; + } case OP_POPCNT32: values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_CTPOP_I32), &lhs, 1, ""); break; diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 8d8425a..1718976 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -1375,6 +1375,10 @@ 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) MINI_OP(OP_XCAST, "xcast", XREG, XREG, NONE) +/* Extract element of vector */ +/* The index is assumed to be in range */ +MINI_OP(OP_XEXTRACT_I32, "xextract_i32", IREG, XREG, IREG) +MINI_OP(OP_XEXTRACT_I64, "xextract_i64", LREG, XREG, IREG) MINI_OP(OP_LZCNT32, "lzcnt32", IREG, IREG, NONE) MINI_OP(OP_LZCNT64, "lzcnt64", LREG, LREG, NONE) diff --git a/src/mono/mono/mini/simd-intrinsics-netcore.c b/src/mono/mono/mini/simd-intrinsics-netcore.c index 96b020f..f1df047 100644 --- a/src/mono/mono/mini/simd-intrinsics-netcore.c +++ b/src/mono/mono/mini/simd-intrinsics-netcore.c @@ -273,7 +273,7 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig MonoInst *ins; MonoType *type, *etype; MonoClass *klass; - int size, len, id, index; + int size, len, id; gboolean is_unsigned; id = lookup_intrins (vector_t_methods, sizeof (vector_t_methods), cmethod); @@ -311,12 +311,20 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig return emit_xcompare (cfg, klass, etype, ins, ins); } case SN_get_Item: - if (args [1]->opcode != OP_ICONST) + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [1]->dreg, len); + MONO_EMIT_NEW_COND_EXC (cfg, GE_UN, "IndexOutOfRangeException"); + if (etype->type == MONO_TYPE_R4 || etype->type == MONO_TYPE_R8) + // FIXME: return NULL; - index = args [1]->inst_c0; - if (index < 0 || index >= len) - return NULL; - return NULL; + // FIXME: Optimize constant case + gboolean is64 = etype->type == MONO_TYPE_I8 || etype->type == MONO_TYPE_U8; + MONO_INST_NEW (cfg, ins, is64 ? OP_XEXTRACT_I64 : OP_XEXTRACT_I32); + ins->dreg = is64 ? alloc_lreg (cfg) : alloc_ireg (cfg); + ins->sreg1 = load_simd_vreg (cfg, cmethod, args [0], NULL); + ins->sreg2 = args [1]->dreg; + ins->type = is64 ? STACK_I8 : STACK_I4; + MONO_ADD_INS (cfg->cbb, ins); + return ins; 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); @@ -651,6 +659,96 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature } #endif +static guint16 vector_128_t_methods [] = { + SN_get_Count, +}; + +static MonoInst* +emit_vector128_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) +{ + MonoInst *ins; + MonoType *type, *etype; + MonoClass *klass; + int size, len, id; + + id = lookup_intrins (vector_128_t_methods, sizeof (vector_128_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; + default: + break; + } + + return NULL; +} + +static guint16 vector_256_t_methods [] = { + SN_get_Count, +}; + +static MonoInst* +emit_vector256_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) +{ + MonoInst *ins; + MonoType *type, *etype; + MonoClass *klass; + int size, len, id; + + id = lookup_intrins (vector_256_t_methods, sizeof (vector_256_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 = 32 / 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; + default: + break; + } + + return NULL; +} + MonoInst* mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { @@ -682,6 +780,12 @@ mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } return ins; } + if (!strcmp (class_ns, "System.Runtime.Intrinsics")) { + if (!strcmp (class_name, "Vector128`1")) + return emit_vector128_t (cfg ,cmethod, fsig, args); + if (!strcmp (class_name, "Vector256`1")) + return emit_vector256_t (cfg ,cmethod, fsig, args); + } #ifdef TARGET_AMD64 if (cmethod->klass->nested_in) class_ns = m_class_get_name_space (cmethod->klass->nested_in), class_name, cmethod->klass->nested_in; -- 2.7.4