[mono] RuntimeHelpers.CreateSpan<T> is now intrinsic. (#81695)
authorJan Dupej <109523496+jandupej@users.noreply.github.com>
Mon, 13 Feb 2023 12:37:33 +0000 (13:37 +0100)
committerGitHub <noreply@github.com>
Mon, 13 Feb 2023 12:37:33 +0000 (13:37 +0100)
* [mono] RuntimeHelpers.CreateSpan is now intrinsic.

* [mono][jit] RuntimeHelpers.CreateSpan intrinsic fixes.

* [mono][jit] RuntimeHelpers.CreateSpan is intrinsic and seems to work.

* [mono] Fixed a warning that broke build.

* [mono] Pointer arithmetic warnings hopefully solved.

* [mono] Fix pointer conversion warning, take 2.

* [mono] RuntimeHelpers.CreateSpan<T> is no longer intrinsic under AOT.

* [mono] RuntimeHelpers.CreateSpan<T> now constructs the result in a safer way.

* [mono][aot] RuntimeHelpers.CreateSpan<T> intrinsic fixed for AOT case.

* [mono] Cleaned up whitespace changes in decompose.c, YAGNI in ir-emit.h.

* [mono] OP_LDTOKEN_FIELD mini opcode introduced for RuntimeHelpers.CreateSpan<T>

* [mono][aot] RuntimeHelpers.CreateSpan<T> intrinsic now emits the correct AOT constant.

* [mono] RuntimeHelpers.CreateSpan intrinsic, removed superfluous sanity checks.

src/mono/mono/mini/decompose.c
src/mono/mono/mini/intrinsics.c
src/mono/mono/mini/ir-emit.h
src/mono/mono/mini/method-to-ir.c
src/mono/mono/mini/mini-ops.h

index ea4b7cd..b4570cc 100644 (file)
@@ -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))
index 8f3b326..e003caf 100644 (file)
@@ -1010,6 +1010,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 ()) {
index 3add579..937222f 100644 (file)
@@ -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)
index 5e55944..a107dd9 100644 (file)
@@ -10901,9 +10901,16 @@ field_access_end:
                                        } 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;
                                }
                        }
 
index 9f32834..e630737 100644 (file)
@@ -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. */