From 60ecb575ad6ff9528ef502084c7626309e51f153 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Fri, 16 Apr 2021 12:32:57 +0300 Subject: [PATCH 1/6] [interp] Try emitting ldc_0 instead of initlocal if possible Unlike initlocal ldc_0 are propagated, also having smaller instruction footprint. Signal retry of cprop when we are adding such instructions, also in other cases. We could dynamically update the state, but let's not overcomplicate the cprop pass, for now. --- src/mono/mono/mini/interp/transform.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 90f8a056bc35e6..f4bccc6aa48c25 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8189,6 +8189,7 @@ interp_cprop (TransformData *td) td->local_ref_count = local_ref_count; retry: + needs_retry = FALSE; memset (local_ref_count, 0, td->locals_size * sizeof (int)); if (td->verbose_level) @@ -8357,13 +8358,20 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/ldfld pair :\n\t"); dump_interp_inst (ins); } + needs_retry = TRUE; } } else if (opcode == MINT_INITOBJ) { InterpInst *ldloca = local_defs [sregs [0]].ins; if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int size = ins->data [0]; int local = ldloca->sregs [0]; - // Replace LDLOCA + INITOBJ with INITLOCAL - ins->opcode = MINT_INITLOCAL; + // Replace LDLOCA + INITOBJ with or LDC + if (size <= 4) + ins->opcode = MINT_LDC_I4_0; + else if (size <= 8) + ins->opcode = MINT_LDC_I8_0; + else + ins->opcode = MINT_INITLOCAL; local_ref_count [sregs [0]]--; ins->dreg = local; @@ -8371,6 +8379,7 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/initobj pair :\n\t"); dump_interp_inst (ins); } + needs_retry = TRUE; } } else if (opcode == MINT_LDOBJ_VT) { InterpInst *ldloca = local_defs [sregs [0]].ins; @@ -8385,6 +8394,7 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/ldobj_vt pair :\n\t"); dump_interp_inst (ins); } + needs_retry = TRUE; } } else if (MINT_IS_STFLD (opcode) && ins->data [0] == 0) { InterpInst *ldloca = local_defs [sregs [0]].ins; @@ -8403,13 +8413,14 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/stfld pair (off %p) :\n\t", ldloca->il_offset); dump_interp_inst (ins); } + needs_retry = TRUE; } } ins_index++; } } - needs_retry = interp_local_deadce (td); + needs_retry |= interp_local_deadce (td); if (mono_interp_opt & INTERP_OPT_BBLOCKS) needs_retry |= interp_optimize_bblocks (td); From 26b6675176d35f7a5a946bf1884072e81d4ba227 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Fri, 16 Apr 2021 17:14:14 +0300 Subject: [PATCH 2/6] [interp] Also update def_index when swapping dreg --- src/mono/mono/mini/interp/transform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index f4bccc6aa48c25..39105c8ad9f37c 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8296,9 +8296,11 @@ interp_cprop (TransformData *td) local_defs [dreg].type = LOCAL_VALUE_NONE; local_defs [dreg].ins = def; + local_defs [dreg].def_index = local_defs [original_dreg].def_index; local_defs [original_dreg].type = LOCAL_VALUE_LOCAL; local_defs [original_dreg].ins = ins; local_defs [original_dreg].local = dreg; + local_defs [original_dreg].def_index = ins_index; local_ref_count [original_dreg]--; local_ref_count [dreg]++; From af5ef4cdd0278b55bbf36e46229c7a5158682c44 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 26 Apr 2021 15:05:05 +0300 Subject: [PATCH 3/6] [interp] Refactor special static field access On netcore, there are no context static fields so all special static fields are thread static. These thread static accessors are not very common, so just remove redundant opcodes for them, and use ldind/ldobj.vt and stind/stobj.vt instead. --- src/mono/mono/mini/interp/interp.c | 73 +--------------- src/mono/mono/mini/interp/mintops.def | 26 +----- src/mono/mono/mini/interp/transform.c | 116 +++++++++++--------------- 3 files changed, 55 insertions(+), 160 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index fe813407e2d65b..6b16b248a4ae06 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -5241,9 +5241,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDSSFLDA) { - guint32 offset = READ32(ip + 2); - LOCAL_VAR (ip [1], gpointer) = mono_get_special_static_data (offset); + MINT_IN_CASE(MINT_LDTSFLDA) { + MonoInternalThread *thread = mono_thread_internal_current (); + guint32 offset = READ32 (ip + 2); + LOCAL_VAR (ip [1], gpointer) = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); ip += 4; MINT_IN_BREAK; } @@ -5278,38 +5279,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define LDTSFLD(datatype, fieldtype) { \ - MonoInternalThread *thread = mono_thread_internal_current (); \ - guint32 offset = READ32 (ip + 2); \ - gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ - LOCAL_VAR (ip [1], datatype) = *(fieldtype*)addr; \ - ip += 4; \ - } - MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(gint32, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(gint32, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(gint32, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(gint32, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(gint32, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(gint64, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(float, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(double, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(gpointer, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDSSFLD) { - guint32 offset = READ32(ip + 3); - gpointer addr = mono_get_special_static_data (offset); - MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [2]]; - stackval_from_data (field->type, (stackval*)(locals + ip [1]), addr, FALSE); - ip += 5; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDSSFLD_VT) { - guint32 offset = READ32(ip + 2); - gpointer addr = mono_get_special_static_data (offset); - memcpy (locals + ip [1], addr, ip [4]); - ip += 5; - MINT_IN_BREAK; - } #define STSFLD(datatype, fieldtype) { \ MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; \ INIT_VTABLE (vtable); \ @@ -5336,40 +5305,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define STTSFLD(datatype, fieldtype) { \ - MonoInternalThread *thread = mono_thread_internal_current (); \ - guint32 offset = READ32 (ip + 2); \ - gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ - *(fieldtype*)addr = LOCAL_VAR (ip [1], datatype); \ - ip += 4; \ - } - - MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(gint32, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(gint32, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(gint32, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(gint32, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(gint32, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(gint64, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(float, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(double, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(gpointer, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STSSFLD) { - guint32 offset = READ32(ip + 3); - gpointer addr = mono_get_special_static_data (offset); - MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [2]]; - stackval_to_data (field->type, (stackval*)(locals + ip [1]), addr, FALSE); - ip += 5; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STSSFLD_VT) { - guint32 offset = READ32(ip + 2); - gpointer addr = mono_get_special_static_data (offset); - memcpy (addr, locals + ip [1], ip [4]); - ip += 5; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STOBJ_VT) { MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; mono_value_copy_internal (LOCAL_VAR (ip [1], gpointer), locals + ip [2], c); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index b3076e7b426acb..7e956a59616702 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -87,18 +87,6 @@ OPDEF(MINT_STFLD_VT_NOREF, "stfld.vt.noref", 5, 0, 2, MintOpTwoShorts) OPDEF(MINT_STFLD_I8_UNALIGNED, "stfld.i8.unaligned", 4, 0, 2, MintOpUShortInt) OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 4, 0, 2, MintOpUShortInt) -OPDEF(MINT_LDTSFLD_I1, "ldtsfld.i1", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_U1, "ldtsfld.u1", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_I2, "ldtsfld.i2", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_U2, "ldtsfld.u2", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_I4, "ldtsfld.i4", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_I8, "ldtsfld.i8", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_R4, "ldtsfld.r4", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_R8, "ldtsfld.r8", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDTSFLD_O, "ldtsfld.o", 4, 1, 0, MintOpInt) -OPDEF(MINT_LDSSFLD, "ldssfld", 5, 1, 0, MintOpFieldToken) -OPDEF(MINT_LDSSFLD_VT, "ldssfld.vt", 5, 1, 0, MintOpInt) - OPDEF(MINT_LDSFLD_I1, "ldsfld.i1", 4, 1, 0, MintOpUShortInt) OPDEF(MINT_LDSFLD_U1, "ldsfld.u1", 4, 1, 0, MintOpUShortInt) OPDEF(MINT_LDSFLD_I2, "ldsfld.i2", 4, 1, 0, MintOpUShortInt) @@ -110,18 +98,6 @@ OPDEF(MINT_LDSFLD_R8, "ldsfld.r8", 4, 1, 0, MintOpUShortInt) OPDEF(MINT_LDSFLD_O, "ldsfld.o", 4, 1, 0, MintOpUShortInt) OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 5, 1, 0, MintOpTwoShorts) -OPDEF(MINT_STTSFLD_I1, "sttsfld.i1", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_U1, "sttsfld.u1", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_I2, "sttsfld.i2", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_U2, "sttsfld.u2", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_I4, "sttsfld.i4", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_I8, "sttsfld.i8", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_R4, "sttsfld.r4", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_R8, "sttsfld.r8", 4, 0, 1, MintOpInt) -OPDEF(MINT_STTSFLD_O, "sttsfld.o", 4, 0, 1, MintOpInt) -OPDEF(MINT_STSSFLD, "stssfld", 5, 0, 1, MintOpFieldToken) -OPDEF(MINT_STSSFLD_VT, "stssfld.vt", 5, 0, 1, MintOpInt) - OPDEF(MINT_STSFLD_I1, "stsfld.i1", 4, 0, 1, MintOpUShortInt) OPDEF(MINT_STSFLD_U1, "stsfld.u1", 4, 0, 1, MintOpUShortInt) OPDEF(MINT_STSFLD_I2, "stsfld.i2", 4, 0, 1, MintOpUShortInt) @@ -133,7 +109,7 @@ OPDEF(MINT_STSFLD_R8, "stsfld.r8", 4, 0, 1, MintOpUShortInt) OPDEF(MINT_STSFLD_O, "stsfld.o", 4, 0, 1, MintOpUShortInt) OPDEF(MINT_STSFLD_VT, "stsfld.vt", 5, 0, 1, MintOpTwoShorts) OPDEF(MINT_LDSFLDA, "ldsflda", 4, 1, 0, MintOpTwoShorts) -OPDEF(MINT_LDSSFLDA, "ldssflda", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLDA, "ldtsflda", 4, 1, 0, MintOpInt) OPDEF(MINT_MOV_I1, "mov.i1", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_MOV_U1, "mov.u1", 3, 1, 1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 39105c8ad9f37c..12291b7d4604fb 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1698,6 +1698,32 @@ interp_get_ldind_for_mt (int mt) return -1; } +static int +interp_get_stind_for_mt (int mt) +{ + switch (mt) { + case MINT_TYPE_I1: + case MINT_TYPE_U1: + return MINT_STIND_I1; + case MINT_TYPE_I2: + case MINT_TYPE_U2: + return MINT_STIND_I2; + case MINT_TYPE_I4: + return MINT_STIND_I4; + case MINT_TYPE_I8: + return MINT_STIND_I8; + case MINT_TYPE_R4: + return MINT_STIND_R4; + case MINT_TYPE_R8: + return MINT_STIND_R8; + case MINT_TYPE_O: + return MINT_STIND_REF; + default: + g_assert_not_reached (); + } + return -1; +} + static void interp_emit_ldobj (TransformData *td, MonoClass *klass) { @@ -1731,33 +1757,7 @@ interp_emit_stobj (TransformData *td, MonoClass *klass) interp_add_ins (td, MINT_STOBJ_VT); td->last_ins->data [0] = get_data_item_index (td, klass); } else { - int opcode; - switch (mt) { - case MINT_TYPE_I1: - case MINT_TYPE_U1: - opcode = MINT_STIND_I1; - break; - case MINT_TYPE_I2: - case MINT_TYPE_U2: - opcode = MINT_STIND_I2; - break; - case MINT_TYPE_I4: - opcode = MINT_STIND_I4; - break; - case MINT_TYPE_I8: - opcode = MINT_STIND_I8; - break; - case MINT_TYPE_R4: - opcode = MINT_STIND_R4; - break; - case MINT_TYPE_R8: - opcode = MINT_STIND_R8; - break; - case MINT_TYPE_O: - opcode = MINT_STIND_REF; - break; - default: g_assert_not_reached (); break; - } + int opcode = interp_get_stind_for_mt (mt); interp_add_ins (td, opcode); } td->sp -= 2; @@ -3995,7 +3995,7 @@ interp_emit_ldsflda (TransformData *td, MonoClassField *field, MonoError *error) mono_error_assert_ok (error); g_assert (offset); - interp_add_ins (td, MINT_LDSSFLDA); + interp_add_ins (td, MINT_LDTSFLDA); interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE32_INS(td->last_ins, 0, &offset); } else { @@ -4065,49 +4065,33 @@ interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *fi if (mono_class_field_is_special_static (field)) { guint32 offset = GPOINTER_TO_UINT (mono_special_static_field_get_offset (field, error)); mono_error_assert_ok (error); - g_assert (offset); + g_assert (offset && (offset & 0x80000000) == 0); - // Offset is SpecialStaticOffset - if ((offset & 0x80000000) == 0 && mt != MINT_TYPE_VT) { - // This field is thread static - if (is_load) { - interp_add_ins (td, MINT_LDTSFLD_I1 + mt); - WRITE32_INS(td->last_ins, 0, &offset); - push_type (td, stack_type [mt], field_class); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); - } else { - interp_add_ins (td, MINT_STTSFLD_I1 + mt); - WRITE32_INS(td->last_ins, 0, &offset); - td->sp--; - interp_ins_set_sreg (td->last_ins, td->sp [0].local); - } + // Load address of thread static field + push_simple_type (td, STACK_TYPE_MP); + interp_add_ins (td, MINT_LDTSFLDA); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + WRITE32_INS (td->last_ins, 0, &offset); + + // Do a load/store to this address + if (is_load) { + int opcode = (mt == MINT_TYPE_VT) ? MINT_LDOBJ_VT : interp_get_ldind_for_mt (mt); + interp_add_ins (td, opcode); + interp_ins_set_sreg (td->last_ins, td->sp [-1].local); + td->sp--; + push_simple_type (td, stack_type [mt]); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = get_data_item_index (td, field_class); } else { + int opcode = (mt == MINT_TYPE_VT) ? MINT_STOBJ_VT : interp_get_stind_for_mt (mt); + interp_add_ins (td, opcode); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [1].local, td->sp [0].local); if (mt == MINT_TYPE_VT) { int size = mono_class_value_size (field_class, NULL); g_assert (size < G_MAXUINT16); - if (is_load) { - interp_add_ins (td, MINT_LDSSFLD_VT); - push_type_vt (td, field_class, size); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); - } else { - interp_add_ins (td, MINT_STSSFLD_VT); - td->sp--; - interp_ins_set_sreg (td->last_ins, td->sp [0].local); - } - WRITE32_INS(td->last_ins, 0, &offset); - td->last_ins->data [2] = size; - } else { - if (is_load) { - interp_add_ins (td, MINT_LDSSFLD); - push_type (td, stack_type [mt], field_class); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); - } else { - interp_add_ins (td, MINT_STSSFLD); - td->sp--; - interp_ins_set_sreg (td->last_ins, td->sp [0].local); - } - td->last_ins->data [0] = get_data_item_index (td, field); - WRITE32_INS(td->last_ins, 1, &offset); + td->last_ins->data [0] = size; } } } else { From ab5954dac22cefe65d3d80c92b331d2234564993 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 26 Apr 2021 16:46:22 +0300 Subject: [PATCH 4/6] [interp] Remove MINT_LDFLD_VT_* opcodes These opcodes were used for loading a field of a VT var. This means the opcodes were loading a value from an immediate offset added to a var offset. We can use the standard MINT_MOV opcodes for this, however we need to resolve the offsets at the very end, so it doesn't interfere with other compilation passes, since the final offset is not the real offset of a variable, but rather an offset inside a VT var. --- src/mono/mono/mini/interp/interp.c | 33 ++++----------------------- src/mono/mono/mini/interp/mintops.def | 15 ++---------- src/mono/mono/mini/interp/transform.c | 32 ++++++++++++++++++++------ 3 files changed, 31 insertions(+), 49 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 6b16b248a4ae06..44824a4669dc80 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -5125,35 +5125,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -// FIXME squash to load directly field type, LDFLD_VT is just a LDLOC -#define LDFLD_VT_UNALIGNED(datatype, fieldtype, unaligned) do { \ - if (unaligned) \ - memcpy (locals + ip [1], (char *)locals + ip [2] + ip [3], sizeof (fieldtype)); \ - else \ - LOCAL_VAR (ip [1], datatype) = LOCAL_VAR (ip [2] + ip [3], fieldtype); \ - ip += 4; \ -} while (0) - -#define LDFLD_VT(datatype, fieldtype) LDFLD_VT_UNALIGNED(datatype, fieldtype, FALSE) - - MINT_IN_CASE(MINT_LDFLD_VT_I1) LDFLD_VT(gint32, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_U1) LDFLD_VT(gint32, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I2) LDFLD_VT(gint32, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_U2) LDFLD_VT(gint32, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I4) LDFLD_VT(gint32, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I8) LDFLD_VT(gint64, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_R4) LDFLD_VT(float, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_R8) LDFLD_VT(double, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_O) LDFLD_VT(gpointer, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I8_UNALIGNED) LDFLD_VT_UNALIGNED(gint64, gint64, TRUE); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_R8_UNALIGNED) LDFLD_VT_UNALIGNED(double, double, TRUE); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDFLD_VT_VT) { - memmove (locals + ip [1], locals + ip [2] + ip [3], ip [4]); - ip += 5; - MINT_IN_BREAK; - } - #define LDFLD_UNALIGNED(datatype, fieldtype, unaligned) do { \ MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); \ NULL_CHECK (o); \ @@ -6481,6 +6452,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip += 3; MINT_IN_BREAK; + MINT_IN_CASE(MINT_MOV_OFF) + // This opcode is resolved to a normal MINT_MOV when emitting compacted instructions + g_assert_not_reached (); + MINT_IN_BREAK; #define MOV(argtype1,argtype2) \ LOCAL_VAR (ip [1], argtype1) = LOCAL_VAR (ip [2], argtype2); \ diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 7e956a59616702..02eff25bd09a37 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -44,19 +44,6 @@ OPDEF(MINT_LDC_R8, "ldc.r8", 6, 1, 0, MintOpDouble) OPDEF(MINT_INIT_ARGLIST, "init_arglist", 3, 1, 0, MintOpNoArgs) -OPDEF(MINT_LDFLD_VT_I1, "ldfld.vt.i1", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_U1, "ldfld.vt.u1", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_I2, "ldfld.vt.i2", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_U2, "ldfld.vt.u2", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_I4, "ldfld.vt.i4", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_I8, "ldfld.vt.i8", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_R4, "ldfld.vt.r4", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_R8, "ldfld.vt.r8", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_O, "ldfld.vt.o", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_VT, "ldfld.vt.vt", 5, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_I8_UNALIGNED, "ldfld.vt.i8.unaligned", 4, 1, 1, MintOpShortInt) -OPDEF(MINT_LDFLD_VT_R8_UNALIGNED, "ldfld.vt.r8.unaligned", 4, 1, 1, MintOpShortInt) - OPDEF(MINT_LDFLD_I1, "ldfld.i1", 4, 1, 1, MintOpUShortInt) OPDEF(MINT_LDFLD_U1, "ldfld.u1", 4, 1, 1, MintOpUShortInt) OPDEF(MINT_LDFLD_I2, "ldfld.i2", 4, 1, 1, MintOpUShortInt) @@ -111,6 +98,8 @@ OPDEF(MINT_STSFLD_VT, "stsfld.vt", 5, 0, 1, MintOpTwoShorts) OPDEF(MINT_LDSFLDA, "ldsflda", 4, 1, 0, MintOpTwoShorts) OPDEF(MINT_LDTSFLDA, "ldtsflda", 4, 1, 0, MintOpInt) +OPDEF(MINT_MOV_OFF, "mov.off", 6, 1, 1, MintOpTwoShorts) + OPDEF(MINT_MOV_I1, "mov.i1", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_MOV_U1, "mov.u1", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_MOV_I2, "mov.i2", 3, 1, 1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 12291b7d4604fb..32274bc4614f6b 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -5896,23 +5896,24 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_emit_sfld_access (td, field, field_klass, mt, TRUE, error); goto_if_nok (error, exit); } else if (td->sp [-1].type == STACK_TYPE_VT) { + int size = 0; /* First we pop the vt object from the stack. Then we push the field */ - int opcode = MINT_LDFLD_VT_I1 + mt - MINT_TYPE_I1; #ifdef NO_UNALIGNED_ACCESS if (field->offset % SIZEOF_VOID_P != 0) { - if (mt == MINT_TYPE_I8) - opcode = MINT_LDFLD_VT_I8_UNALIGNED; - else if (mt == MINT_TYPE_R8) - opcode = MINT_LDFLD_VT_R8_UNALIGNED; + if (mt == MINT_TYPE_I8 || mt == MINT_TYPE_R8) + size = 8; } #endif - interp_add_ins (td, opcode); + interp_add_ins (td, MINT_MOV_OFF); g_assert (m_class_is_valuetype (klass)); td->sp--; interp_ins_set_sreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = field->offset - MONO_ABI_SIZEOF (MonoObject); + td->last_ins->data [1] = mt; if (mt == MINT_TYPE_VT) - td->last_ins->data [1] = field_size; + size = field_size; + td->last_ins->data [2] = size; + if (mt == MINT_TYPE_VT) push_type_vt (td, field_klass, field_size); else @@ -7605,6 +7606,23 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp); cbb->last_seq_point = seqp; + } else if (opcode == MINT_MOV_OFF) { + int foff = ins->data [0]; + int mt = ins->data [1]; + int fsize = ins->data [2]; + + int dest_off = td->locals [ins->dreg].offset; + int src_off = td->locals [ins->sregs [0]].offset + foff; + if (mt == MINT_TYPE_VT || fsize) + opcode = MINT_MOV_VT; + else + opcode = get_mov_for_type (mt, TRUE); + // Replace MINT_MOV_OFF with the real instruction + ip [-1] = opcode; + *ip++ = dest_off; + *ip++ = src_off; + if (opcode == MINT_MOV_VT) + *ip++ = fsize; #ifdef ENABLE_EXPERIMENT_TIERED } else if (ins->flags & INTERP_INST_FLAG_RECORD_CALL_PATCH) { g_assert (MINT_IS_PATCHABLE_CALL (opcode)); From 360b16c4baa0d6bd44d3d4d66e725b5bfb54520a Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 26 Apr 2021 16:56:50 +0300 Subject: [PATCH 5/6] [interp] Remove MINT_CHECKPOINT opcode It was used to check for abort requests during backward branches. Also stop checking for abort requests in other places. --- src/mono/mono/mini/interp/interp.c | 10 ---------- src/mono/mono/mini/interp/mintops.def | 1 - src/mono/mono/mini/interp/transform.c | 2 -- 3 files changed, 13 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 44824a4669dc80..0e522b4a920cdb 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -5089,14 +5089,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs THROW_EX (ex, ip); MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CHECKPOINT) - /* Do synchronous checking of abort requests */ - EXCEPTION_CHECKPOINT; - ++ip; - MINT_IN_BREAK; MINT_IN_CASE(MINT_SAFEPOINT) - /* Do synchronous checking of abort requests */ - EXCEPTION_CHECKPOINT; if (G_UNLIKELY (mono_polling_required)) { context_set_safepoint_frame (context, frame); /* Poll safepoint */ @@ -6094,9 +6087,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK; ip += short_offset ? (gint16)*(ip + 1) : (gint32)READ32 (ip + 1); - // Check for any abort requests, once all finally blocks were invoked - if (!check) - EXCEPTION_CHECKPOINT; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ICALL_V_V) diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 02eff25bd09a37..721cdfee6dda93 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -165,7 +165,6 @@ OPDEF(MINT_RETHROW, "rethrow", 2, 0, 0, MintOpUShortInt) OPDEF(MINT_ENDFINALLY, "endfinally", 2, 0, 0, MintOpShortInt) OPDEF(MINT_MONO_RETHROW, "mono_rethrow", 2, 0, 1, MintOpNoArgs) -OPDEF(MINT_CHECKPOINT, "checkpoint", 1, 0, 0, MintOpNoArgs) OPDEF(MINT_SAFEPOINT, "safepoint", 1, 0, 0, MintOpNoArgs) OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 4, 0, 1, MintOpBranch) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 32274bc4614f6b..7f2f732c98aa5c 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -789,8 +789,6 @@ handle_branch (TransformData *td, int short_op, int long_op, int offset) if (offset < 0) { if (mono_threads_are_safepoints_enabled ()) interp_add_ins (td, MINT_SAFEPOINT); - else - interp_add_ins (td, MINT_CHECKPOINT); } InterpBasicBlock *target_bb = td->offset_to_bb [target]; From e7782b4779084858b4437a5c2253c38006bd171e Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Fri, 30 Apr 2021 21:47:54 +0300 Subject: [PATCH 6/6] [interp] Add super instructions for conditional branches We include the safepoint in the instruction and also the immediate comparison value if possible. Doing the safepoint by default in branching opcodes is questionable since, in a typical program, forward branches are far more common than backward branches. We should really remove many of the branching opcodes. We now have the possibility to swap the src vars order, and use the opposite comparison instead. --- src/mono/mono/mini/interp/interp.c | 96 +++++++++++++++++-- src/mono/mono/mini/interp/mintops.def | 50 ++++++++++ src/mono/mono/mini/interp/mintops.h | 3 +- src/mono/mono/mini/interp/transform.c | 133 +++++++++++++++++++++++++- 4 files changed, 274 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 0e522b4a920cdb..ec422ef1a7771a 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1022,6 +1022,22 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con } \ } while (0) +// Reduce duplicate code in interp_exec_method +static void +do_safepoint (InterpFrame *frame, ThreadContext *context) +{ + context_set_safepoint_frame (context, frame); + /* Poll safepoint */ + mono_threads_safepoint (); + context_clear_safepoint_frame (context); +} + +#define SAFEPOINT \ + do { \ + if (G_UNLIKELY (mono_polling_required)) \ + do_safepoint (frame, context); \ + } while (0) + static MonoObject* ves_array_create (MonoClass *klass, int param_count, stackval *values, MonoError *error) { @@ -4136,6 +4152,79 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs CONDBR(mono_isunordered (d1, d2) || d1 < d2) MINT_IN_BREAK; } + +#define ZEROP_SP(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op 0) { \ + gint16 br_offset = (gint16) ip [2]; \ + BACK_BRANCH_PROFILE (br_offset); \ + SAFEPOINT; \ + ip += br_offset; \ + } else \ + ip += 3; + +MINT_IN_CASE(MINT_BRFALSE_I4_SP) ZEROP_SP(gint32, ==); MINT_IN_BREAK; +MINT_IN_CASE(MINT_BRFALSE_I8_SP) ZEROP_SP(gint64, ==); MINT_IN_BREAK; +MINT_IN_CASE(MINT_BRTRUE_I4_SP) ZEROP_SP(gint32, !=); MINT_IN_BREAK; +MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; + +#define CONDBR_SP(cond) \ + if (cond) { \ + gint16 br_offset = (gint16) ip [3]; \ + BACK_BRANCH_PROFILE (br_offset); \ + SAFEPOINT; \ + ip += br_offset; \ + } else \ + ip += 4; +#define BRELOP_SP(datatype, op) \ + CONDBR_SP(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) + + MINT_IN_CASE(MINT_BEQ_I4_SP) BRELOP_SP(gint32, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8_SP) BRELOP_SP(gint64, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I4_SP) BRELOP_SP(gint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8_SP) BRELOP_SP(gint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I4_SP) BRELOP_SP(gint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8_SP) BRELOP_SP(gint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I4_SP) BRELOP_SP(gint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8_SP) BRELOP_SP(gint64, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I4_SP) BRELOP_SP(gint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8_SP) BRELOP_SP(gint64, <=); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_BNE_UN_I4_SP) BRELOP_SP(guint32, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8_SP) BRELOP_SP(guint64, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I4_SP) BRELOP_SP(guint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8_SP) BRELOP_SP(guint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I4_SP) BRELOP_SP(guint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8_SP) BRELOP_SP(guint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I4_SP) BRELOP_SP(guint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8_SP) BRELOP_SP(guint64, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I4_SP) BRELOP_SP(guint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8_SP) BRELOP_SP(guint64, <); MINT_IN_BREAK; + +#define BRELOP_IMM_SP(datatype, op) \ + CONDBR_SP(LOCAL_VAR (ip [1], datatype) op (datatype)(gint16)ip [2]) + + MINT_IN_CASE(MINT_BEQ_I4_IMM_SP) BRELOP_IMM_SP(gint32, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8_IMM_SP) BRELOP_IMM_SP(gint64, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I4_IMM_SP) BRELOP_IMM_SP(gint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8_IMM_SP) BRELOP_IMM_SP(gint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I4_IMM_SP) BRELOP_IMM_SP(gint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8_IMM_SP) BRELOP_IMM_SP(gint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I4_IMM_SP) BRELOP_IMM_SP(gint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8_IMM_SP) BRELOP_IMM_SP(gint64, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I4_IMM_SP) BRELOP_IMM_SP(gint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8_IMM_SP) BRELOP_IMM_SP(gint64, <=); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_BNE_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_SWITCH) { guint32 val = LOCAL_VAR (ip [1], guint32); guint32 n = READ32 (ip + 2); @@ -5090,12 +5179,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } MINT_IN_CASE(MINT_SAFEPOINT) - if (G_UNLIKELY (mono_polling_required)) { - context_set_safepoint_frame (context, frame); - /* Poll safepoint */ - mono_threads_safepoint (); - context_clear_safepoint_frame (context); - } + SAFEPOINT; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLDA_UNSAFE) { diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 721cdfee6dda93..aeb5f034e2b9db 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -269,6 +269,56 @@ OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 4, 0, 2, MintOpShortBranch) OPDEF(MINT_BLT_UN_R4_S, "blt.un.r4.s", 4, 0, 2, MintOpShortBranch) OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I4_SP, "brfalse.i4.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I8_SP, "brfalse.i8.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I4_SP, "brtrue.i4.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I8_SP, "brtrue.i8.sp", 3, 0, 1, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4_SP, "beq.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_I8_SP, "beq.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I4_SP, "bge.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I8_SP, "bge.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I4_SP, "bgt.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I8_SP, "bgt.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I4_SP, "blt.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I8_SP, "blt.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I4_SP, "ble.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I8_SP, "ble.i8.sp", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BNE_UN_I4_SP, "bne.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_I8_SP, "bne.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I4_SP, "bge.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I8_SP, "bge.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I4_SP, "bgt.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I8_SP, "bgt.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I4_SP, "ble.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I8_SP, "ble.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I4_SP, "blt.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I8_SP, "blt.un.i8.sp", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4_IMM_SP, "beq.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BEQ_I8_IMM_SP, "beq.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_I4_IMM_SP, "bge.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_I8_IMM_SP, "bge.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_I4_IMM_SP, "bgt.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_I8_IMM_SP, "bgt.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_I4_IMM_SP, "blt.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_I8_IMM_SP, "blt.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_I4_IMM_SP, "ble.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_I8_IMM_SP, "ble.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) + +OPDEF(MINT_BNE_UN_I4_IMM_SP, "bne.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BNE_UN_I8_IMM_SP, "bne.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_UN_I4_IMM_SP, "bge.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_UN_I8_IMM_SP, "bge.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_UN_I4_IMM_SP, "bgt.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_UN_I8_IMM_SP, "bgt.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_UN_I4_IMM_SP, "ble.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_UN_I8_IMM_SP, "ble.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_UN_I4_IMM_SP, "blt.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_UN_I8_IMM_SP, "blt.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) + + OPDEF(MINT_SWITCH, "switch", 0, 0, 1, MintOpSwitch) OPDEF(MINT_LDSTR, "ldstr", 3, 1, 0, MintOpShortInt) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index 621fa930119e12..ec5c95298c0467 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -23,7 +23,8 @@ typedef enum MintOpFieldToken, MintOpClassToken, MintOpTwoShorts, - MintOpShortAndInt + MintOpShortAndInt, + MintOpShortAndShortBranch } MintOpArgType; #define OPDEF(a,b,c,d,e,f) a, diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 7f2f732c98aa5c..ac95364038ed7e 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1403,6 +1403,15 @@ dump_interp_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, g g_string_append_printf (str, ")"); break; } + case MintOpShortAndShortBranch: + if (ins) { + /* the target IL is already embedded in the instruction */ + g_string_append_printf (str, " %u, BB%d", *(guint16*)data, ins->info.target_bb->index); + } else { + target = ins_offset + *(gint16*)(data + 1); + g_string_append_printf (str, " %u, IR_%04x", *(guint16*)data, target); + } + break; default: g_string_append_printf (str, "unknown arg type\n"); } @@ -7540,10 +7549,14 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in } } else if ((opcode >= MINT_BRFALSE_I4_S && opcode <= MINT_BRTRUE_R8_S) || (opcode >= MINT_BEQ_I4_S && opcode <= MINT_BLT_UN_R8_S) || + (opcode >= MINT_BRFALSE_I4_SP && opcode <= MINT_BLT_UN_I8_IMM_SP) || opcode == MINT_BR_S || opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK || opcode == MINT_CALL_HANDLER_S) { const int br_offset = start_ip - td->new_code; + gboolean has_imm = opcode >= MINT_BEQ_I4_IMM_SP && opcode <= MINT_BLT_UN_I8_IMM_SP; for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) *ip++ = td->locals [ins->sregs [i]].offset; + if (has_imm) + *ip++ = ins->data [0]; if (ins->info.target_bb->native_offset >= 0) { // Backwards branch. We can already patch it. *ip++ = ins->info.target_bb->native_offset - br_offset; @@ -7551,7 +7564,7 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in // We don't know the in_offset of the target, add a reloc Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc)); reloc->type = RELOC_SHORT_BRANCH; - reloc->skip = mono_interp_op_sregs [opcode]; + reloc->skip = mono_interp_op_sregs [opcode] + has_imm; reloc->offset = br_offset; reloc->target_bb = ins->info.target_bb; g_ptr_array_add (td->relocs, reloc); @@ -8459,6 +8472,74 @@ get_sreg_imm (TransformData *td, int sreg, gint16 *imm) return FALSE; } +static int +get_binop_condbr_imm_sp (int opcode) +{ + switch (opcode) { + case MINT_BEQ_I4_S: return MINT_BEQ_I4_IMM_SP; + case MINT_BEQ_I8_S: return MINT_BEQ_I8_IMM_SP; + case MINT_BGE_I4_S: return MINT_BGE_I4_IMM_SP; + case MINT_BGE_I8_S: return MINT_BGE_I8_IMM_SP; + case MINT_BGT_I4_S: return MINT_BGT_I4_IMM_SP; + case MINT_BGT_I8_S: return MINT_BGT_I8_IMM_SP; + case MINT_BLT_I4_S: return MINT_BLT_I4_IMM_SP; + case MINT_BLT_I8_S: return MINT_BLT_I8_IMM_SP; + case MINT_BLE_I4_S: return MINT_BLE_I4_IMM_SP; + case MINT_BLE_I8_S: return MINT_BLE_I8_IMM_SP; + case MINT_BNE_UN_I4_S: return MINT_BNE_UN_I4_IMM_SP; + case MINT_BNE_UN_I8_S: return MINT_BNE_UN_I8_IMM_SP; + case MINT_BGE_UN_I4_S: return MINT_BGE_UN_I4_IMM_SP; + case MINT_BGE_UN_I8_S: return MINT_BGE_UN_I8_IMM_SP; + case MINT_BGT_UN_I4_S: return MINT_BGT_UN_I4_IMM_SP; + case MINT_BGT_UN_I8_S: return MINT_BGT_UN_I8_IMM_SP; + case MINT_BLE_UN_I4_S: return MINT_BLE_UN_I4_IMM_SP; + case MINT_BLE_UN_I8_S: return MINT_BLE_UN_I8_IMM_SP; + case MINT_BLT_UN_I4_S: return MINT_BLT_UN_I4_IMM_SP; + case MINT_BLT_UN_I8_S: return MINT_BLT_UN_I8_IMM_SP; + default: return MINT_NOP; + } +} + +static int +get_binop_condbr_sp (int opcode) +{ + switch (opcode) { + case MINT_BEQ_I4_S: return MINT_BEQ_I4_SP; + case MINT_BEQ_I8_S: return MINT_BEQ_I8_SP; + case MINT_BGE_I4_S: return MINT_BGE_I4_SP; + case MINT_BGE_I8_S: return MINT_BGE_I8_SP; + case MINT_BGT_I4_S: return MINT_BGT_I4_SP; + case MINT_BGT_I8_S: return MINT_BGT_I8_SP; + case MINT_BLT_I4_S: return MINT_BLT_I4_SP; + case MINT_BLT_I8_S: return MINT_BLT_I8_SP; + case MINT_BLE_I4_S: return MINT_BLE_I4_SP; + case MINT_BLE_I8_S: return MINT_BLE_I8_SP; + case MINT_BNE_UN_I4_S: return MINT_BNE_UN_I4_SP; + case MINT_BNE_UN_I8_S: return MINT_BNE_UN_I8_SP; + case MINT_BGE_UN_I4_S: return MINT_BGE_UN_I4_SP; + case MINT_BGE_UN_I8_S: return MINT_BGE_UN_I8_SP; + case MINT_BGT_UN_I4_S: return MINT_BGT_UN_I4_SP; + case MINT_BGT_UN_I8_S: return MINT_BGT_UN_I8_SP; + case MINT_BLE_UN_I4_S: return MINT_BLE_UN_I4_SP; + case MINT_BLE_UN_I8_S: return MINT_BLE_UN_I8_SP; + case MINT_BLT_UN_I4_S: return MINT_BLT_UN_I4_SP; + case MINT_BLT_UN_I8_S: return MINT_BLT_UN_I8_SP; + default: return MINT_NOP; + } +} + +static int +get_unop_condbr_sp (int opcode) +{ + switch (opcode) { + case MINT_BRFALSE_I4_S: return MINT_BRFALSE_I4_SP; + case MINT_BRFALSE_I8_S: return MINT_BRFALSE_I8_SP; + case MINT_BRTRUE_I4_S: return MINT_BRTRUE_I4_SP; + case MINT_BRTRUE_I8_S: return MINT_BRTRUE_I8_SP; + default: return MINT_NOP; + } +} + static void interp_super_instructions (TransformData *td) { @@ -8641,6 +8722,56 @@ interp_super_instructions (TransformData *td) local_ref_count [obj_sreg]--; mono_interp_stats.super_instructions++; } + } else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (opcode)) { + gint16 imm; + int sreg_imm = ins->sregs [1]; + if (get_sreg_imm (td, sreg_imm, &imm)) { + int condbr_op = get_binop_condbr_imm_sp (opcode); + if (condbr_op != MINT_NOP) { + InterpInst *prev_ins = interp_prev_ins (ins); + // The new instruction does a safepoint + if (prev_ins && prev_ins->opcode == MINT_SAFEPOINT) + interp_clear_ins (prev_ins); + InterpInst *new_ins = interp_insert_ins (td, ins, condbr_op); + new_ins->sregs [0] = ins->sregs [0]; + new_ins->data [0] = imm; + new_ins->info.target_bb = ins->info.target_bb; + interp_clear_ins (td->locals [sreg_imm].def); + interp_clear_ins (ins); + local_ref_count [sreg_imm]--; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (new_ins); + } + } + } else { + InterpInst *prev_ins = interp_prev_ins (ins); + if (prev_ins && prev_ins->opcode == MINT_SAFEPOINT) { + int condbr_op = get_binop_condbr_sp (opcode); + if (condbr_op != MINT_NOP) { + interp_clear_ins (prev_ins); + ins->opcode = condbr_op; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (ins); + } + } + } + } + } else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (opcode)) { + InterpInst *prev_ins = interp_prev_ins (ins); + if (prev_ins && prev_ins->opcode == MINT_SAFEPOINT) { + int condbr_op = get_unop_condbr_sp (opcode); + if (condbr_op != MINT_NOP) { + interp_clear_ins (prev_ins); + ins->opcode = condbr_op; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (ins); + } + } + + } } } }