diff --git a/src/mono/mono/mini/decompose.c b/src/mono/mono/mini/decompose.c index ea4b7cdbcb2794..b4570cc0c7429d 100644 --- a/src/mono/mono/mini/decompose.c +++ b/src/mono/mono/mini/decompose.c @@ -1214,6 +1214,10 @@ mono_decompose_vtype_opts (MonoCompile *cfg) mono_simd_decompose_intrinsic (cfg, bb, ins); #endif switch (ins->opcode) { + case OP_LDTOKEN_FIELD: + ins->opcode = OP_VMOVE; + restart = TRUE; + break; case OP_VMOVE: { g_assert (ins->klass); if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass)) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 86098233ad9658..22248d0624aaf3 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -1008,6 +1008,49 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign EMIT_NEW_UNALU (cfg, ins, OP_ICGT, dreg, -1); ins->type = STACK_I4; return ins; + } else if (!strcmp (cmethod->name, "CreateSpan") && fsig->param_count == 1) { + MonoGenericContext* ctx = mono_method_get_context (cmethod); + g_assert (ctx); + g_assert (ctx->method_inst); + g_assert (ctx->method_inst->type_argc == 1); + MonoType* arg_type = ctx->method_inst->type_argv [0]; + MonoType* t = mini_get_underlying_type (arg_type); + g_assert (!MONO_TYPE_IS_REFERENCE (t) && t->type != MONO_TYPE_VALUETYPE); + + // This OP_LDTOKEN_FIELD later changes into a OP_VMOVE. + MonoClassField* field = (MonoClassField*) args [0]->inst_p1; + if (args [0]->opcode != OP_LDTOKEN_FIELD) + return NULL; + + int alignment = 0; + const int element_size = mono_type_size (t, &alignment); + const int num_elements = mono_type_size (field->type, &alignment) / element_size; + const int obj_size = MONO_ABI_SIZEOF (MonoObject); + + MonoInst* span = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL); + MonoInst* span_addr; + EMIT_NEW_TEMPLOADA (cfg, span_addr, span->inst_c0); + + MonoInst* ptr_inst; + if (cfg->compile_aot) { + NEW_RVACONST (cfg, ptr_inst, mono_class_get_image (mono_field_get_parent (field)), args [0]->inst_c0); + MONO_ADD_INS (cfg->cbb, ptr_inst); + } else { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + const int swizzle = 1; +#else + const int swizzle = element_size; +#endif + gpointer data_ptr = (gpointer)mono_field_get_rva (field, swizzle); + EMIT_NEW_PCONST (cfg, ptr_inst, data_ptr); + } + + MonoClassField* field_ref = mono_class_get_field_from_name_full (span->klass, "_reference", NULL); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, span_addr->dreg, field_ref->offset - obj_size, ptr_inst->dreg); + MonoClassField* field_len = mono_class_get_field_from_name_full (span->klass, "_length", NULL); + MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, span_addr->dreg, field_len->offset - obj_size, num_elements); + EMIT_NEW_TEMPLOAD (cfg, ins, span->inst_c0); + return ins; } else return NULL; } else if (cmethod->klass == mono_class_try_get_memory_marshal_class ()) { diff --git a/src/mono/mono/mini/ir-emit.h b/src/mono/mono/mini/ir-emit.h index 3add579bdee399..937222f568c22e 100644 --- a/src/mono/mono/mini/ir-emit.h +++ b/src/mono/mono/mini/ir-emit.h @@ -307,6 +307,8 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), NULL, STACK_OBJ, mono_defaults.string_class) +#define NEW_RVACONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_RVA, (image), (token), NULL, STACK_MP, NULL) + #define NEW_LDSTRLITCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_LDSTR_LIT, (val)) #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token,generic_context) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), (generic_context), STACK_OBJ, mono_defaults.runtimetype_class) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index d7cb653f79d025..311bf8f69bdd12 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -10820,9 +10820,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } else { EMIT_NEW_PCONST (cfg, ins, handle); } + EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg); EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0); + ins->opcode = OP_LDTOKEN_FIELD; + ins->inst_c0 = n; + ins->inst_p1 = handle; + + cfg->flags |= MONO_CFG_NEEDS_DECOMPOSE; + cfg->cbb->needs_decompose = TRUE; } } diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 7db9500b41bae4..42cf9d4e5fa295 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -795,6 +795,7 @@ MINI_OP(OP_LOAD_GOTADDR, "load_gotaddr", IREG, NONE, NONE) MINI_OP(OP_DUMMY_USE, "dummy_use", NONE, IREG, NONE) MINI_OP(OP_NOT_REACHED, "not_reached", NONE, NONE, NONE) MINI_OP(OP_NOT_NULL, "not_null", NONE, IREG, NONE) +MINI_OP(OP_LDTOKEN_FIELD, "ldtoken_field", VREG, VREG, NONE) /* SIMD opcodes. */