From 197787457d5fa708515cf2b098c89a5d70c1671e Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Sat, 22 Oct 2022 00:29:22 +0300 Subject: [PATCH 1/3] [mono][interp] Improve GETITEM_SPAN intrinsic Field offsets are known at compile time, they don't need to be included in the code stream. --- src/mono/mono/mini/interp/interp.c | 10 +++------- src/mono/mono/mini/interp/mintops.def | 2 +- src/mono/mono/mini/interp/transform.c | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 0efeb187b99af..cca6e039d1bff 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -6065,19 +6065,15 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; int index = LOCAL_VAR (ip [3], int); NULL_CHECK (span); - gsize offset_length = (gsize)(gint16)ip [5]; - - const gint32 length = *(gint32 *) (span + offset_length); + const gint32 length = *(gint32 *) (span + TARGET_SIZEOF_VOID_P); if (index < 0 || index >= length) THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); gsize element_size = (gsize)(gint16)ip [4]; - gsize offset_pointer = (gsize)(gint16)ip [6]; - - const gpointer pointer = *(gpointer *)(span + offset_pointer); + gpointer pointer = *(gpointer *)span; LOCAL_VAR (ip [1], gpointer) = (guint8 *) pointer + index * element_size; - ip += 7; + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STRLEN) { diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index d6188995716a2..49269be6e6807 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -414,7 +414,7 @@ OPDEF(MINT_STELEM_VT, "stelem.vt", 6, 0, 3, MintOpTwoShorts) OPDEF(MINT_LDLEN, "ldlen", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_GETITEM_SPAN, "getitem.span", 7, 1, 2, MintOpTwoShorts) +OPDEF(MINT_GETITEM_SPAN, "getitem.span", 5, 1, 2, MintOpTwoShorts) /* binops */ OPDEF(MINT_ADD_I4, "add.i4", 4, 1, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 725e993d392c9..5dba5ae29f879 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2134,16 +2134,16 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoClassField *length_field = mono_class_get_field_from_name_full (target_method->klass, "_length", NULL); g_assert (length_field); int offset_length = m_field_get_offset (length_field) - sizeof (MonoObject); + g_assert (offset_length == TARGET_SIZEOF_VOID_P); MonoClassField *ptr_field = mono_class_get_field_from_name_full (target_method->klass, "_reference", NULL); g_assert (ptr_field); int offset_pointer = m_field_get_offset (ptr_field) - sizeof (MonoObject); + g_assert (offset_pointer == 0); int size = mono_class_array_element_size (param_class); interp_add_ins (td, MINT_GETITEM_SPAN); td->last_ins->data [0] = GINT_TO_UINT16 (size); - td->last_ins->data [1] = GINT_TO_UINT16 (offset_length); - td->last_ins->data [2] = GINT_TO_UINT16 (offset_pointer); td->sp -= 2; interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); From 6dc712fa7873285e30306861c8f1699957d0e190 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Sat, 22 Oct 2022 00:59:48 +0300 Subject: [PATCH 2/3] [mono][interp] Add version of getitemspan that doesn't use indirection --- src/mono/mono/mini/interp/interp.c | 16 ++++++++++++++++ src/mono/mono/mini/interp/mintops.def | 1 + src/mono/mono/mini/interp/transform.c | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index cca6e039d1bff..f6bf99bf1aee9 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -6076,6 +6076,22 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; ip += 5; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_GETITEM_LOCALSPAN) { + // Same as getitem span but we know the offset of the span structure on the stack + guint8 *span = (guint8*)locals + ip [2]; + int index = LOCAL_VAR (ip [3], int); + + gint32 length = *(gint32 *) (span + TARGET_SIZEOF_VOID_P); + if (index < 0 || index >= length) + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); + + gsize element_size = (gsize)(gint16)ip [4]; + gpointer pointer = *(gpointer *)span; + LOCAL_VAR (ip [1], gpointer) = (guint8 *) pointer + index * element_size; + + ip += 5; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_STRLEN) { MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 49269be6e6807..016f263d5c377 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -415,6 +415,7 @@ OPDEF(MINT_STELEM_VT, "stelem.vt", 6, 0, 3, MintOpTwoShorts) OPDEF(MINT_LDLEN, "ldlen", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_GETITEM_SPAN, "getitem.span", 5, 1, 2, MintOpTwoShorts) +OPDEF(MINT_GETITEM_LOCALSPAN, "getitem.localspan", 5, 1, 2, MintOpTwoShorts) /* binops */ OPDEF(MINT_ADD_I4, "add.i4", 4, 1, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 5dba5ae29f879..e4fcb8c6f3ff7 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8996,6 +8996,17 @@ interp_cprop (TransformData *td) } needs_retry = TRUE; } + } else if (opcode == MINT_GETITEM_SPAN) { + InterpInst *ldloca = local_defs [sregs [0]].ins; + if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int local = ldloca->sregs [0]; + // Allow ldloca instruction to be killed + local_ref_count [sregs [0]]--; + // Instead of loading from the indirect pointer pass directly the vt var + ins->opcode = MINT_GETITEM_LOCALSPAN; + sregs [0] = local; + needs_retry = TRUE; + } } ins_index++; } From e42b814a9937b80eb961b1b829bce7a84f667b19 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Sat, 22 Oct 2022 11:28:40 +0300 Subject: [PATCH 3/3] [mono][interp] Add general MonoSpanOfVoid struct and use it in interp opcodes --- src/mono/mono/metadata/object-internals.h | 1 + src/mono/mono/mini/interp/interp.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 7725b25946369..4c161f4669457 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -176,6 +176,7 @@ struct _MonoArray { } name; MONO_DEFINE_SPAN_OF_T (MonoSpanOfObjects, MonoObject*) +MONO_DEFINE_SPAN_OF_T (MonoSpanOfVoid, void) #define MONO_SIZEOF_MONO_ARRAY (MONO_STRUCT_OFFSET_CONSTANT (MonoArray, vector)) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index f6bf99bf1aee9..52ccda878605b 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -6061,33 +6061,31 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_BREAK; } MINT_IN_CASE(MINT_GETITEM_SPAN) { - guint8 *span = LOCAL_VAR (ip [2], guint8*); + MonoSpanOfVoid *span = LOCAL_VAR (ip [2], MonoSpanOfVoid*); int index = LOCAL_VAR (ip [3], int); NULL_CHECK (span); - const gint32 length = *(gint32 *) (span + TARGET_SIZEOF_VOID_P); + gint32 length = span->_length; if (index < 0 || index >= length) THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); gsize element_size = (gsize)(gint16)ip [4]; - gpointer pointer = *(gpointer *)span; - LOCAL_VAR (ip [1], gpointer) = (guint8 *) pointer + index * element_size; + LOCAL_VAR (ip [1], gpointer) = (guint8*)span->_reference + index * element_size; ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_GETITEM_LOCALSPAN) { // Same as getitem span but we know the offset of the span structure on the stack - guint8 *span = (guint8*)locals + ip [2]; + MonoSpanOfVoid *span = (MonoSpanOfVoid*)(locals + ip [2]); int index = LOCAL_VAR (ip [3], int); - gint32 length = *(gint32 *) (span + TARGET_SIZEOF_VOID_P); + gint32 length = span->_length; if (index < 0 || index >= length) THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); gsize element_size = (gsize)(gint16)ip [4]; - gpointer pointer = *(gpointer *)span; - LOCAL_VAR (ip [1], gpointer) = (guint8 *) pointer + index * element_size; + LOCAL_VAR (ip [1], gpointer) = (guint8*)span->_reference + index * element_size; ip += 5; MINT_IN_BREAK;