From fdc7b3289dd99165fb26b1347039d41b983bb82d Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 7 Apr 2021 13:41:37 +0300 Subject: [PATCH 1/8] [interp] Replace ldloca + initobj pair with initlocal We do it in the cprop pass because ldloca removal can enable additional copy propagations. --- src/mono/mono/mini/interp/interp.c | 1 + src/mono/mono/mini/interp/mintops.def | 1 + src/mono/mono/mini/interp/transform.c | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 78f24a129f9b5b..c85942743e1632 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3189,6 +3189,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MintOpcode opcode; DUMP_INSTR(); MINT_IN_SWITCH (*ip) { + MINT_IN_CASE(MINT_INITLOCAL) MINT_IN_CASE(MINT_INITLOCALS) memset (locals + ip [1], 0, ip [2]); ip += 3; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index b373bb5e2b6e58..e90a2fe93dba15 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -327,6 +327,7 @@ OPDEF(MINT_STOBJ_VT, "stobj.vt", 4, 0, 2, MintOpClassToken) OPDEF(MINT_CPBLK, "cpblk", 4, 0, 3, MintOpNoArgs) OPDEF(MINT_INITBLK, "initblk", 4, 0, 3, MintOpNoArgs) OPDEF(MINT_LOCALLOC, "localloc", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INITLOCAL, "initlocal", 3, 1, 0, MintOpShortInt) OPDEF(MINT_INITLOCALS, "initlocals", 3, 0, 0, MintOpTwoShorts) OPDEF(MINT_LDELEM_I, "ldelem.i", 4, 1, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 29df42cebaa096..211cbb7868db4e 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8347,7 +8347,21 @@ interp_cprop (TransformData *td) if (td->verbose_level) { g_print ("Replace ldloca/ldfld pair :\n\t"); - dump_interp_inst (ins->next); + dump_interp_inst (ins); + } + } + } else if (opcode == MINT_INITOBJ) { + InterpInst *ldloca = local_defs [sregs [0]].ins; + if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int local = ldloca->sregs [0]; + // Replace LDLOCA + INITOBJ with INITLOCAL + ins->opcode = MINT_INITLOCAL; + local_ref_count [sregs [0]]--; + ins->dreg = local; + + if (td->verbose_level) { + g_print ("Replace ldloca/initobj pair :\n\t"); + dump_interp_inst (ins); } } } else if (MINT_IS_STFLD (opcode) && ins->data [0] == 0) { From 821557beb2eec3268ac126c54c29a1fae6580ee0 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 7 Apr 2021 16:10:14 +0300 Subject: [PATCH 2/8] [interp] Replace ldloca + ldobj.vt with mov.vt --- src/mono/mono/mini/interp/transform.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 211cbb7868db4e..f999591d60203c 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8364,6 +8364,20 @@ interp_cprop (TransformData *td) dump_interp_inst (ins); } } + } else if (opcode == MINT_LDOBJ_VT) { + InterpInst *ldloca = local_defs [sregs [0]].ins; + if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int local = ldloca->sregs [0]; + // Replace LDLOCA + LDOBJ_VT with MOV_VT + ins->opcode = MINT_MOV_VT; + local_ref_count [sregs [0]]--; + sregs [0] = local; + + if (td->verbose_level) { + g_print ("Replace ldloca/ldobj_vt pair :\n\t"); + dump_interp_inst (ins); + } + } } else if (MINT_IS_STFLD (opcode) && ins->data [0] == 0) { InterpInst *ldloca = local_defs [sregs [0]].ins; if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S && From 6165fcbb95a99e3142bf3ee4fe258883a51853c4 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 7 Apr 2021 16:21:03 +0300 Subject: [PATCH 3/8] [interp] Add superinstructions for multiplication with constant --- src/mono/mono/mini/interp/interp.c | 8 ++++++++ src/mono/mono/mini/interp/mintops.def | 3 +++ src/mono/mono/mini/interp/transform.c | 14 +++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index c85942743e1632..c42798303bbac6 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4371,6 +4371,14 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_MUL_I8) BINOP(gint64, *); MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_I4_IMM) + LOCAL_VAR (ip [1], gint32) = LOCAL_VAR (ip [2], gint32) * (gint16)ip [3]; + ip += 4; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_I8_IMM) + LOCAL_VAR (ip [1], gint64) = LOCAL_VAR (ip [2], gint64) * (gint16)ip [3]; + ip += 4; + MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_R4) BINOP(float, *); MINT_IN_BREAK; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index e90a2fe93dba15..d30182d5540a08 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -604,6 +604,9 @@ OPDEF(MINT_RET_I8_IMM, "ret.i8.imm", 2, 0, 0, MintOpShortInt) OPDEF(MINT_ADD_I4_IMM, "add.i4.imm", 4, 1, 1, MintOpShortInt) OPDEF(MINT_ADD_I8_IMM, "add.i8.imm", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_MUL_I4_IMM, "mul.i4.imm", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_MUL_I8_IMM, "mul.i8.imm", 4, 1, 1, MintOpShortInt) + OPDEF(MINT_SHR_UN_I4_IMM, "shr.un.i4.imm", 4, 1, 1, MintOpShortInt) OPDEF(MINT_SHR_UN_I8_IMM, "shr.un.i8.imm", 4, 1, 1, MintOpShortInt) OPDEF(MINT_SHL_I4_IMM, "shl.i4.imm", 4, 1, 1, MintOpShortInt) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index f999591d60203c..ba971f57eb81f2 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8475,7 +8475,8 @@ interp_super_instructions (TransformData *td) dump_interp_inst (new_inst); } } - } else if (opcode == MINT_ADD_I4 || opcode == MINT_ADD_I8) { + } else if (opcode == MINT_ADD_I4 || opcode == MINT_ADD_I8 || + opcode == MINT_MUL_I4 || opcode == MINT_MUL_I8) { int sreg = -1; int sreg_imm = -1; gint16 imm; @@ -8487,8 +8488,15 @@ interp_super_instructions (TransformData *td) sreg_imm = ins->sregs [1]; } if (sreg != -1) { - int add_op = opcode == MINT_ADD_I4 ? MINT_ADD_I4_IMM : MINT_ADD_I8_IMM; - InterpInst *new_inst = interp_insert_ins (td, ins, add_op); + int binop; + switch (opcode) { + case MINT_ADD_I4: binop = MINT_ADD_I4_IMM; break; + case MINT_ADD_I8: binop = MINT_ADD_I8_IMM; break; + case MINT_MUL_I4: binop = MINT_MUL_I4_IMM; break; + case MINT_MUL_I8: binop = MINT_MUL_I8_IMM; break; + default: g_assert_not_reached (); + } + InterpInst *new_inst = interp_insert_ins (td, ins, binop); new_inst->dreg = ins->dreg; new_inst->sregs [0] = sreg; new_inst->data [0] = imm; From e91e3ee80f9173178c8ecf24918fff651062e476 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 7 Apr 2021 16:26:19 +0300 Subject: [PATCH 4/8] [interp] Remove redundant opcode --- src/mono/mono/mini/interp/interp.c | 5 ----- src/mono/mono/mini/interp/mintops.def | 1 - src/mono/mono/mini/interp/transform.c | 6 +++++- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index c42798303bbac6..9492a9fcb17fc7 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4894,11 +4894,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip += 4;; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) { - LOCAL_VAR (ip [1], gpointer) = LOCAL_VAR (ip [2], guint8*) + LOCAL_VAR (ip [3], mono_u); - ip += 4; - MINT_IN_BREAK; - } MINT_IN_CASE(MINT_INTRINS_CLEAR_WITH_REFERENCES) { gpointer p = LOCAL_VAR (ip [1], gpointer); size_t size = LOCAL_VAR (ip [2], mono_u) * sizeof (gpointer); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index d30182d5540a08..c8d93875c4baad 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -741,7 +741,6 @@ OPDEF(MINT_INTRINS_ENUM_HASFLAG, "intrins_enum_hasflag", 5, 1, 2, MintOpClassTok OPDEF(MINT_INTRINS_GET_HASHCODE, "intrins_get_hashcode", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_INTRINS_GET_TYPE, "intrins_get_type", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_INTRINS_SPAN_CTOR, "intrins_span_ctor", 4, 1, 2, MintOpNoArgs) -OPDEF(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET, "intrins_unsafe_add_byte_offset", 4, 1, 2, MintOpNoArgs) OPDEF(MINT_INTRINS_UNSAFE_BYTE_OFFSET, "intrins_unsafe_byte_offset", 4, 1, 2, MintOpNoArgs) OPDEF(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE, "intrins_runtimehelpers_object_has_component_size", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_INTRINS_CLEAR_WITH_REFERENCES, "intrin_clear_with_references", 3, 0, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index ba971f57eb81f2..495941f0792a5a 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2279,7 +2279,11 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas || !strcmp (klass_name_space, "System.Runtime.CompilerServices")) && !strcmp (klass_name, "Unsafe")) { if (!strcmp (tm, "AddByteOffset")) - *op = MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET; +#if SIZEOF_VOID_P == 4 + *op = MINT_ADD_I4; +#else + *op = MINT_ADD_I8; +#endif else if (!strcmp (tm, "ByteOffset")) *op = MINT_INTRINS_UNSAFE_BYTE_OFFSET; else if (!strcmp (tm, "As") || !strcmp (tm, "AsRef")) From bad97b1179d6aa045ca990b6565a9cddfab7cc80 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 7 Apr 2021 17:41:28 +0300 Subject: [PATCH 5/8] [interp] Update indirects count if removing bblock with ldloca If the var no longer has indirects, we might be able to do cprop through it --- src/mono/mono/mini/interp/transform.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 495941f0792a5a..bb65fc1e1d8f15 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -639,14 +639,27 @@ interp_unlink_bblocks (InterpBasicBlock *from, InterpBasicBlock *to) to->in_count--; } -static void +static gboolean interp_remove_bblock (TransformData *td, InterpBasicBlock *bb, InterpBasicBlock *prev_bb) { + gboolean needs_cprop = FALSE; + g_assert (!bb->in_count); + for (InterpInst *ins = bb->first_ins; ins != NULL; ins = ins->next) { + if (ins->opcode == MINT_LDLOCA_S) { + td->locals [ins->sregs [0]].indirects--; + if (!td->locals [ins->sregs [0]].indirects) { + // We can do cprop now through this local. Run cprop again. + needs_cprop = TRUE; + } + } + } while (bb->out_count) interp_unlink_bblocks (bb, bb->out_bb [0]); prev_bb->next_bb = bb->next_bb; mark_bb_as_dead (td, bb); + + return needs_cprop; } static void @@ -7706,7 +7719,7 @@ interp_optimize_bblocks (TransformData *td) if (next_bb->in_count == 0 && !next_bb->eh_block) { if (td->verbose_level) g_print ("Removed BB%d\n", next_bb->index); - interp_remove_bblock (td, next_bb, bb); + needs_cprop |= interp_remove_bblock (td, next_bb, bb); continue; } else if (bb->out_count == 1 && bb->out_bb [0] == next_bb && next_bb->in_count == 1 && !next_bb->eh_block) { g_assert (next_bb->in_bb [0] == bb); From 6572d2fd7b75c7cb8a039d165f9259e267677e5c Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 13 Apr 2021 20:19:58 +0300 Subject: [PATCH 6/8] [interp] Refactor ldind/stind opcodes Remove some unnecessary opcodes. Always do a null check when dereferencing pointers with ldind. Having an unsafe version of this is really useless performance wise and can only be used in very few cases. --- src/mono/mono/mini/interp/interp.c | 185 ++++++++------------------ src/mono/mono/mini/interp/mintops.def | 22 ++- src/mono/mono/mini/interp/transform.c | 52 ++++---- 3 files changed, 87 insertions(+), 172 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 9492a9fcb17fc7..2b344f61bf3a92 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4149,101 +4149,48 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDIND_I1_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], int) = *(gint8*)ptr; - ip += 3; +#define LDIND(datatype,casttype,unaligned) do { \ + gpointer ptr = LOCAL_VAR (ip [2], gpointer); \ + NULL_CHECK (ptr); \ + if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \ + memcpy (locals + ip [1], ptr, sizeof (datatype)); \ + else \ + LOCAL_VAR (ip [1], datatype) = *(casttype*)ptr; \ + ip += 3; \ +} while (0) + MINT_IN_CASE(MINT_LDIND_I1) + LDIND(int, gint8, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_U1_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], int) = *(guint8*)ptr; - ip += 3; + MINT_IN_CASE(MINT_LDIND_U1) + LDIND(int, guint8, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_I2_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], int) = *(gint16*)ptr; - ip += 3; + MINT_IN_CASE(MINT_LDIND_I2) + LDIND(int, gint16, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_U2_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], int) = *(guint16*)ptr; - ip += 3; + MINT_IN_CASE(MINT_LDIND_U2) + LDIND(int, guint16, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */ - MINT_IN_CASE(MINT_LDIND_U4_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], int) = *(gint32*)ptr; - ip += 3; + MINT_IN_CASE(MINT_LDIND_I4) { + LDIND(int, gint32, FALSE); MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDIND_I8_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); + MINT_IN_CASE(MINT_LDIND_I8) #ifdef NO_UNALIGNED_ACCESS - if ((gsize)ptr % SIZEOF_VOID_P) - memcpy (locals + ip [1], ptr, sizeof (gint64)); - else -#endif - LOCAL_VAR (ip [1], gint64) = *(gint64*)ptr; - ip += 3; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_I) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - LOCAL_VAR (ip [1], gpointer) = *(gpointer*)ptr; - ip += 3; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_I8) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); -#ifdef NO_UNALIGNED_ACCESS - if ((gsize)ptr % SIZEOF_VOID_P) - memcpy (locals + ip [1], ptr, sizeof (gint64)); - else + LDIND(gint64, gint64, TRUE); +#else + LDIND(gint64, gint64, FALSE); #endif - LOCAL_VAR (ip [1], gint64) = *(gint64*)ptr; - ip += 3; MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_R4_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], float) = *(gfloat*)ptr; - ip += 3; + MINT_IN_CASE(MINT_LDIND_R4) + LDIND(float, gfloat, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_R8_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); + MINT_IN_CASE(MINT_LDIND_R8) #ifdef NO_UNALIGNED_ACCESS - if ((gsize)ptr % SIZEOF_VOID_P) - memcpy (locals + ip [1], ptr, sizeof (gdouble)); - else + LDIND(double, gdouble, TRUE); +#else + LDIND(double, gdouble, FALSE); #endif - LOCAL_VAR (ip [1], double) = *(gdouble*)ptr; - ip += 3; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_REF) - LOCAL_VAR (ip [1], gpointer) = *(gpointer*)LOCAL_VAR (ip [2], gpointer); - ip += 3; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_REF_CHECK) { - gpointer ptr = LOCAL_VAR (ip [2], gpointer); - NULL_CHECK (ptr); - LOCAL_VAR (ip [1], gpointer) = *(gpointer*)LOCAL_VAR (ip [2], gpointer); - ip += 3; MINT_IN_BREAK; - } MINT_IN_CASE(MINT_STIND_REF) { gpointer ptr = LOCAL_VAR (ip [1], gpointer); NULL_CHECK (ptr); @@ -4251,65 +4198,41 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip += 3; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_STIND_I1) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); - *(gint8*)ptr = LOCAL_VAR (ip [2], gint8); - ip += 3; +#define STIND(datatype,unaligned) do { \ + gpointer ptr = LOCAL_VAR (ip [1], gpointer); \ + NULL_CHECK (ptr); \ + if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \ + memcpy (ptr, locals + ip [2], sizeof (datatype)); \ + else \ + *(datatype*)ptr = LOCAL_VAR (ip [2], datatype); \ + ip += 3; \ +} while (0) + MINT_IN_CASE(MINT_STIND_I1) + STIND(gint8, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STIND_I2) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); - *(gint16*)ptr = LOCAL_VAR (ip [2], gint16); - ip += 3; + MINT_IN_CASE(MINT_STIND_I2) + STIND(gint16, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STIND_I4) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); - *(gint32*)ptr = LOCAL_VAR (ip [2], gint32); - ip += 3; + MINT_IN_CASE(MINT_STIND_I4) + STIND(gint32, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STIND_I) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); - *(mono_i*)ptr = LOCAL_VAR (ip [2], mono_i); - ip += 3; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STIND_I8) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); + MINT_IN_CASE(MINT_STIND_I8) #ifdef NO_UNALIGNED_ACCESS - if ((gsize)ptr % SIZEOF_VOID_P) - memcpy (ptr, locals + ip [2], sizeof (gint64)); - else + STIND(gint64, TRUE); +#else + STIND(gint64, FALSE); #endif - *(gint64*)ptr = LOCAL_VAR (ip [2], gint64); - ip += 3; MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STIND_R4) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); - *(float*)ptr = LOCAL_VAR (ip [2], float); - ip += 3; + MINT_IN_CASE(MINT_STIND_R4) + STIND(float, FALSE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STIND_R8) { - gpointer ptr = LOCAL_VAR (ip [1], gpointer); - NULL_CHECK (ptr); + MINT_IN_CASE(MINT_STIND_R8) #ifdef NO_UNALIGNED_ACCESS - if ((gsize)ptr % SIZEOF_VOID_P) - memcpy (ptr, locals + ip [2], sizeof (double)); - else + STIND(double, TRUE); +#else + STIND(double, FALSE); #endif - *(double*)ptr = LOCAL_VAR (ip [2], double); - ip += 3; MINT_IN_BREAK; - } MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4) mono_atomic_store_i32 (LOCAL_VAR (ip [1], gint32*), LOCAL_VAR (ip [2], gint32)); ip += 3; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index c8d93875c4baad..7ed07d1b5dc880 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -145,25 +145,19 @@ OPDEF(MINT_MOV_VT, "mov.vt", 4, 1, 1, MintOpShortInt) OPDEF(MINT_LDLOCA_S, "ldloca.s", 3, 1, 0, MintOpUShortInt) -OPDEF(MINT_LDIND_I1_CHECK, "ldind.i1.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_U1_CHECK, "ldind.u1.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I2_CHECK, "ldind.i2.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_U2_CHECK, "ldind.u2.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I4_CHECK, "ldind.i4.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_U4_CHECK, "ldind.u4.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I8_CHECK, "ldind.i8.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I, "ldind.i", 3, 1, 1, MintOpUShortInt) -OPDEF(MINT_LDIND_I8, "ldind.i8", 3, 1, 1, MintOpUShortInt) -OPDEF(MINT_LDIND_R4_CHECK, "ldind.r4.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_R8_CHECK, "ldind.r8.check", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_REF, "ldind.ref", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_LDIND_REF_CHECK, "ldind.ref.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I1, "ldind.i1", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U1, "ldind.u1", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I2, "ldind.i2", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U2, "ldind.u2", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I4, "ldind.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I8, "ldind.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_R4, "ldind.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_R8, "ldind.r8", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_STIND_I1, "stind.i1", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_I2, "stind.i2", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_I4, "stind.i4", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_I8, "stind.i8", 3, 0, 2, MintOpNoArgs) -OPDEF(MINT_STIND_I, "stind.i", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_R4, "stind.r4", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_R8, "stind.r8", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_REF, "stind.ref", 3, 0, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index bb65fc1e1d8f15..585aa242d5245d 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -132,14 +132,14 @@ MonoInterpStats mono_interp_stats; #if SIZEOF_VOID_P == 8 #define MINT_MOV_P MINT_MOV_8 -#else -#define MINT_MOV_P MINT_MOV_4 -#endif - -#if SIZEOF_VOID_P == 8 #define MINT_LDNULL MINT_LDC_I8_0 +#define MINT_LDIND_I MINT_LDIND_I8 +#define MINT_STIND_I MINT_STIND_I8 #else +#define MINT_MOV_P MINT_MOV_4 #define MINT_LDNULL MINT_LDC_I4_0 +#define MINT_LDIND_I MINT_LDIND_I4 +#define MINT_STIND_I MINT_STIND_I4 #endif typedef struct { @@ -1681,15 +1681,15 @@ static int interp_get_ldind_for_mt (int mt) { switch (mt) { - case MINT_TYPE_I1: return MINT_LDIND_I1_CHECK; - case MINT_TYPE_U1: return MINT_LDIND_U1_CHECK; - case MINT_TYPE_I2: return MINT_LDIND_I2_CHECK; - case MINT_TYPE_U2: return MINT_LDIND_U2_CHECK; - case MINT_TYPE_I4: return MINT_LDIND_I4_CHECK; - case MINT_TYPE_I8: return MINT_LDIND_I8_CHECK; - case MINT_TYPE_R4: return MINT_LDIND_R4_CHECK; - case MINT_TYPE_R8: return MINT_LDIND_R8_CHECK; - case MINT_TYPE_O: return MINT_LDIND_REF; + case MINT_TYPE_I1: return MINT_LDIND_I1; + case MINT_TYPE_U1: return MINT_LDIND_U1; + case MINT_TYPE_I2: return MINT_LDIND_I2; + case MINT_TYPE_U2: return MINT_LDIND_U2; + case MINT_TYPE_I4: return MINT_LDIND_I4; + case MINT_TYPE_I8: return MINT_LDIND_I8; + case MINT_TYPE_R4: return MINT_LDIND_R4; + case MINT_TYPE_R8: return MINT_LDIND_R8; + case MINT_TYPE_O: return MINT_LDIND_I; default: g_assert_not_reached (); } @@ -5050,37 +5050,35 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; } case CEE_LDIND_I1: - handle_ldind (td, MINT_LDIND_I1_CHECK, STACK_TYPE_I4, &volatile_); + handle_ldind (td, MINT_LDIND_I1, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_U1: - handle_ldind (td, MINT_LDIND_U1_CHECK, STACK_TYPE_I4, &volatile_); + handle_ldind (td, MINT_LDIND_U1, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_I2: - handle_ldind (td, MINT_LDIND_I2_CHECK, STACK_TYPE_I4, &volatile_); + handle_ldind (td, MINT_LDIND_I2, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_U2: - handle_ldind (td, MINT_LDIND_U2_CHECK, STACK_TYPE_I4, &volatile_); + handle_ldind (td, MINT_LDIND_U2, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_I4: - handle_ldind (td, MINT_LDIND_I4_CHECK, STACK_TYPE_I4, &volatile_); - break; case CEE_LDIND_U4: - handle_ldind (td, MINT_LDIND_U4_CHECK, STACK_TYPE_I4, &volatile_); + handle_ldind (td, MINT_LDIND_I4, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_I8: - handle_ldind (td, MINT_LDIND_I8_CHECK, STACK_TYPE_I8, &volatile_); + handle_ldind (td, MINT_LDIND_I8, STACK_TYPE_I8, &volatile_); break; case CEE_LDIND_I: - handle_ldind (td, MINT_LDIND_REF_CHECK, STACK_TYPE_I, &volatile_); + handle_ldind (td, MINT_LDIND_I, STACK_TYPE_I, &volatile_); break; case CEE_LDIND_R4: - handle_ldind (td, MINT_LDIND_R4_CHECK, STACK_TYPE_R4, &volatile_); + handle_ldind (td, MINT_LDIND_R4, STACK_TYPE_R4, &volatile_); break; case CEE_LDIND_R8: - handle_ldind (td, MINT_LDIND_R8_CHECK, STACK_TYPE_R8, &volatile_); + handle_ldind (td, MINT_LDIND_R8, STACK_TYPE_R8, &volatile_); break; case CEE_LDIND_REF: - handle_ldind (td, MINT_LDIND_REF_CHECK, STACK_TYPE_O, &volatile_); + handle_ldind (td, MINT_LDIND_I, STACK_TYPE_O, &volatile_); break; case CEE_STIND_REF: handle_stind (td, MINT_STIND_REF, &volatile_); @@ -5492,7 +5490,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->last_ins->data [0] = get_data_item_index(td, klass); } else { td->sp--; - interp_add_ins (td, MINT_LDIND_REF); + interp_add_ins (td, MINT_LDIND_I); interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_simple_type (td, STACK_TYPE_I); interp_ins_set_dreg (td->last_ins, td->sp [-1].local); From b6bef73bdcf5cf0781f1949aa328dbcc99d79ea7 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 14 Apr 2021 15:45:35 +0300 Subject: [PATCH 7/8] [interp] Add super instructions for ldind/stind with offset --- src/mono/mono/mini/interp/interp.c | 120 ++++++++++++++++++++++++++ src/mono/mono/mini/interp/mintops.def | 24 ++++++ src/mono/mono/mini/interp/mintops.h | 2 + src/mono/mono/mini/interp/transform.c | 60 +++++++++++++ 4 files changed, 206 insertions(+) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 2b344f61bf3a92..693c643c68a31f 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4189,6 +4189,72 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs LDIND(double, gdouble, TRUE); #else LDIND(double, gdouble, FALSE); +#endif + MINT_IN_BREAK; + +#define LDIND_OFFSET(datatype,casttype,unaligned) do { \ + gpointer ptr = LOCAL_VAR (ip [2], gpointer); \ + NULL_CHECK (ptr); \ + ptr = (char*)ptr + LOCAL_VAR (ip [3], mono_i); \ + if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \ + memcpy (locals + ip [1], ptr, sizeof (datatype)); \ + else \ + LOCAL_VAR (ip [1], datatype) = *(casttype*)ptr; \ + ip += 4; \ +} while (0) + MINT_IN_CASE(MINT_LDIND_OFFSET_I1) + LDIND_OFFSET(int, gint8, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_U1) + LDIND_OFFSET(int, guint8, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_I2) + LDIND_OFFSET(int, gint16, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_U2) + LDIND_OFFSET(int, guint16, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_I4) + LDIND_OFFSET(int, gint32, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_I8) +#ifdef NO_UNALIGNED_ACCESS + LDIND_OFFSET(gint64, gint64, TRUE); +#else + LDIND_OFFSET(gint64, gint64, FALSE); +#endif + MINT_IN_BREAK; + +#define LDIND_OFFSET_IMM(datatype,casttype,unaligned) do { \ + gpointer ptr = LOCAL_VAR (ip [2], gpointer); \ + NULL_CHECK (ptr); \ + ptr = (char*)ptr + (gint16)ip [3]; \ + if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \ + memcpy (locals + ip [1], ptr, sizeof (datatype)); \ + else \ + LOCAL_VAR (ip [1], datatype) = *(casttype*)ptr; \ + ip += 4; \ +} while (0) + MINT_IN_CASE(MINT_LDIND_OFFSET_IMM_I1) + LDIND_OFFSET_IMM(int, gint8, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_IMM_U1) + LDIND_OFFSET_IMM(int, guint8, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_IMM_I2) + LDIND_OFFSET_IMM(int, gint16, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_IMM_U2) + LDIND_OFFSET_IMM(int, guint16, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_IMM_I4) + LDIND_OFFSET_IMM(int, gint32, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_OFFSET_IMM_I8) +#ifdef NO_UNALIGNED_ACCESS + LDIND_OFFSET_IMM(gint64, gint64, TRUE); +#else + LDIND_OFFSET_IMM(gint64, gint64, FALSE); #endif MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_REF) { @@ -4231,6 +4297,60 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs STIND(double, TRUE); #else STIND(double, FALSE); +#endif + MINT_IN_BREAK; + +#define STIND_OFFSET(datatype,unaligned) do { \ + gpointer ptr = LOCAL_VAR (ip [1], gpointer); \ + NULL_CHECK (ptr); \ + ptr = (char*)ptr + LOCAL_VAR (ip [2], mono_i); \ + if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \ + memcpy (ptr, locals + ip [3], sizeof (datatype)); \ + else \ + *(datatype*)ptr = LOCAL_VAR (ip [3], datatype); \ + ip += 4; \ +} while (0) + MINT_IN_CASE(MINT_STIND_OFFSET_I1) + STIND_OFFSET(gint8, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_OFFSET_I2) + STIND_OFFSET(gint16, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_OFFSET_I4) + STIND_OFFSET(gint32, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_OFFSET_I8) +#ifdef NO_UNALIGNED_ACCESS + STIND_OFFSET(gint64, TRUE); +#else + STIND_OFFSET(gint64, FALSE); +#endif + MINT_IN_BREAK; + +#define STIND_OFFSET_IMM(datatype,unaligned) do { \ + gpointer ptr = LOCAL_VAR (ip [1], gpointer); \ + NULL_CHECK (ptr); \ + ptr = (char*)ptr + (gint16)ip [3]; \ + if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \ + memcpy (ptr, locals + ip [2], sizeof (datatype)); \ + else \ + *(datatype*)ptr = LOCAL_VAR (ip [2], datatype); \ + ip += 4; \ +} while (0) + MINT_IN_CASE(MINT_STIND_OFFSET_IMM_I1) + STIND_OFFSET_IMM(gint8, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_OFFSET_IMM_I2) + STIND_OFFSET_IMM(gint16, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_OFFSET_IMM_I4) + STIND_OFFSET_IMM(gint32, FALSE); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_OFFSET_IMM_I8) +#ifdef NO_UNALIGNED_ACCESS + STIND_OFFSET_IMM(gint64, TRUE); +#else + STIND_OFFSET_IMM(gint64, FALSE); #endif MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4) diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 7ed07d1b5dc880..1dbff5742345a6 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -154,6 +154,20 @@ OPDEF(MINT_LDIND_I8, "ldind.i8", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_LDIND_R4, "ldind.r4", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_LDIND_R8, "ldind.r8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_OFFSET_I1, "ldind_off.i1", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDIND_OFFSET_U1, "ldind_off.u1", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDIND_OFFSET_I2, "ldind_off.i2", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDIND_OFFSET_U2, "ldind_off.u2", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDIND_OFFSET_I4, "ldind_off.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDIND_OFFSET_I8, "ldind_off.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_LDIND_OFFSET_IMM_I1, "ldind_off_imm.i1", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDIND_OFFSET_IMM_U1, "ldind_off_imm.u1", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDIND_OFFSET_IMM_I2, "ldind_off_imm.i2", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDIND_OFFSET_IMM_U2, "ldind_off_imm.u2", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDIND_OFFSET_IMM_I4, "ldind_off_imm.i4", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDIND_OFFSET_IMM_I8, "ldind_off_imm.i8", 4, 1, 1, MintOpShortInt) + OPDEF(MINT_STIND_I1, "stind.i1", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_I2, "stind.i2", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_I4, "stind.i4", 3, 0, 2, MintOpNoArgs) @@ -162,6 +176,16 @@ OPDEF(MINT_STIND_R4, "stind.r4", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_R8, "stind.r8", 3, 0, 2, MintOpNoArgs) OPDEF(MINT_STIND_REF, "stind.ref", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_OFFSET_I1, "stind_off.i1", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STIND_OFFSET_I2, "stind_off.i2", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STIND_OFFSET_I4, "stind_off.i4", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STIND_OFFSET_I8, "stind_off.i8", 4, 0, 3, MintOpNoArgs) + +OPDEF(MINT_STIND_OFFSET_IMM_I1, "stind_off_imm.i1", 4, 0, 2, MintOpShortInt) +OPDEF(MINT_STIND_OFFSET_IMM_I2, "stind_off_imm.i2", 4, 0, 2, MintOpShortInt) +OPDEF(MINT_STIND_OFFSET_IMM_I4, "stind_off_imm.i4", 4, 0, 2, MintOpShortInt) +OPDEF(MINT_STIND_OFFSET_IMM_I8, "stind_off_imm.i8", 4, 0, 2, MintOpShortInt) + OPDEF(MINT_BR, "br", 3, 0, 0, MintOpBranch) OPDEF(MINT_LEAVE, "leave", 3, 0, 0, MintOpBranch) OPDEF(MINT_LEAVE_CHECK, "leave.check", 3, 0, 0, MintOpBranch) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index 15254ba66c0e5e..621fa930119e12 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -67,6 +67,8 @@ typedef enum { #define MINT_IS_BINOP_SHIFT(op) ((op) >= MINT_SHR_UN_I4 && (op) <= MINT_SHR_I8) #define MINT_IS_LDFLD(op) ((op) >= MINT_LDFLD_I1 && (op) <= MINT_LDFLD_O) #define MINT_IS_STFLD(op) ((op) >= MINT_STFLD_I1 && (op) <= MINT_STFLD_O) +#define MINT_IS_LDIND_INT(op) ((op) >= MINT_LDIND_I1 && (op) <= MINT_LDIND_I8) +#define MINT_IS_STIND_INT(op) ((op) >= MINT_STIND_I1 && (op) <= MINT_STIND_I8) #define MINT_CALL_ARGS 2 #define MINT_CALL_ARGS_SREG -2 diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 585aa242d5245d..a1b5251d05e029 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -44,6 +44,7 @@ MonoInterpStats mono_interp_stats; #define MINT_NEG_FP MINT_NEG_R8 #define MINT_ADD_P MINT_ADD_I8 +#define MINT_ADD_P_IMM MINT_ADD_I8_IMM #define MINT_SUB_P MINT_SUB_I8 #define MINT_MUL_P MINT_MUL_I8 #define MINT_DIV_P MINT_DIV_I8 @@ -90,6 +91,7 @@ MonoInterpStats mono_interp_stats; #define MINT_NEG_FP MINT_NEG_R4 #define MINT_ADD_P MINT_ADD_I4 +#define MINT_ADD_P_IMM MINT_ADD_I4_IMM #define MINT_SUB_P MINT_SUB_I4 #define MINT_MUL_P MINT_MUL_I4 #define MINT_DIV_P MINT_DIV_I4 @@ -8559,6 +8561,64 @@ interp_super_instructions (TransformData *td) dump_interp_inst (new_inst); } } + } else if (MINT_IS_LDIND_INT (opcode)) { + int sreg_base = ins->sregs [0]; + InterpInst *def = td->locals [sreg_base].def; + if (def != NULL && td->local_ref_count [sreg_base] == 1) { + InterpInst *new_inst = NULL; + if (def->opcode == MINT_ADD_P) { + int ldind_offset_op = MINT_LDIND_OFFSET_I1 + (opcode - MINT_LDIND_I1); + new_inst = interp_insert_ins (td, ins, ldind_offset_op); + new_inst->dreg = ins->dreg; + new_inst->sregs [0] = def->sregs [0]; // base + new_inst->sregs [1] = def->sregs [1]; // off + } else if (def->opcode == MINT_ADD_P_IMM) { + int ldind_offset_imm_op = MINT_LDIND_OFFSET_IMM_I1 + (opcode - MINT_LDIND_I1); + new_inst = interp_insert_ins (td, ins, ldind_offset_imm_op); + new_inst->dreg = ins->dreg; + new_inst->sregs [0] = def->sregs [0]; // base + new_inst->data [0] = def->data [0]; // imm value + } + if (new_inst) { + interp_clear_ins (def); + interp_clear_ins (ins); + local_ref_count [sreg_base]--; + mono_interp_stats.super_instructions++; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (new_inst); + } + } + } + } else if (MINT_IS_STIND_INT (opcode)) { + int sreg_base = ins->sregs [0]; + InterpInst *def = td->locals [sreg_base].def; + if (def != NULL && td->local_ref_count [sreg_base] == 1) { + InterpInst *new_inst = NULL; + if (def->opcode == MINT_ADD_P) { + int stind_offset_op = MINT_STIND_OFFSET_I1 + (opcode - MINT_STIND_I1); + new_inst = interp_insert_ins (td, ins, stind_offset_op); + new_inst->sregs [0] = def->sregs [0]; // base + new_inst->sregs [1] = def->sregs [1]; // off + new_inst->sregs [2] = ins->sregs [1]; // value + } else if (def->opcode == MINT_ADD_P_IMM) { + int stind_offset_imm_op = MINT_STIND_OFFSET_IMM_I1 + (opcode - MINT_STIND_I1); + new_inst = interp_insert_ins (td, ins, stind_offset_imm_op); + new_inst->sregs [0] = def->sregs [0]; // base + new_inst->sregs [1] = ins->sregs [1]; // value + new_inst->data [0] = def->data [0]; // imm value + } + if (new_inst) { + interp_clear_ins (def); + interp_clear_ins (ins); + local_ref_count [sreg_base]--; + mono_interp_stats.super_instructions++; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (new_inst); + } + } + } } else if (MINT_IS_LDFLD (opcode)) { // cknull + ldfld -> ldfld // FIXME This optimization is very limited, it is meant mainly to remove cknull From 507e484d6688b77635f58c6215acdf97f1d76486 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Thu, 15 Apr 2021 00:24:08 +0300 Subject: [PATCH 8/8] [interp] Remove opcode for conversion from i8 to i4 It is redundant, we replace it with a MOV_8 which will end up being removed by the cprop pass. --- src/mono/mono/mini/interp/interp.c | 5 ----- src/mono/mono/mini/interp/mintops.def | 2 -- src/mono/mono/mini/interp/transform.c | 31 ++++++++------------------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 693c643c68a31f..d9da170345a220 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4687,11 +4687,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs LOCAL_VAR (ip [1], gint32) = (gint32) LOCAL_VAR (ip [2], double); ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U4_I8) - MINT_IN_CASE(MINT_CONV_I4_I8) - LOCAL_VAR (ip [1], gint32) = (gint32) LOCAL_VAR (ip [2], gint64); - ip += 3; - MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U4_R4) #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4 LOCAL_VAR (ip [1], gint32) = mono_rconv_u4 (LOCAL_VAR (ip [2], float)); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 1dbff5742345a6..b3076e7b426acb 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -533,11 +533,9 @@ OPDEF(MINT_CONV_U2_I8, "conv.u2.i8", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_CONV_U2_R4, "conv.u2.r4", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_CONV_U2_R8, "conv.u2.r8", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_CONV_I4_I8, "conv.i4.i8", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_CONV_I4_R4, "conv.i4.r4", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_CONV_I4_R8, "conv.i4.r8", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_CONV_U4_I8, "conv.u4.i8", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_CONV_U4_R4, "conv.u4.r4", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_CONV_U4_R8, "conv.u4.r8", 3, 1, 1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index a1b5251d05e029..a107a07f2dbfd4 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1828,7 +1828,7 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (arg_size > SIZEOF_VOID_P) { // 8 -> 4 switch (type_index) { case 0: case 1: - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); break; case 2: interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_R4_R8); @@ -1912,7 +1912,7 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (src_size > dst_size) { // 8 -> 4 switch (type_index) { case 0: case 1: - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); break; case 2: interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_R8); @@ -5263,7 +5263,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; case STACK_TYPE_I8: #if SIZEOF_VOID_P == 4 - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_MOV_8); #endif break; case STACK_TYPE_MP: @@ -5303,7 +5303,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; case STACK_TYPE_I8: #if SIZEOF_VOID_P == 4 - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_MOV_8); #endif break; default: @@ -5323,11 +5323,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case STACK_TYPE_I4: break; case STACK_TYPE_I8: - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); break; case STACK_TYPE_MP: #if SIZEOF_VOID_P == 8 - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); #else SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); #endif @@ -5349,11 +5349,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case STACK_TYPE_I4: break; case STACK_TYPE_I8: - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); break; case STACK_TYPE_MP: #if SIZEOF_VOID_P == 8 - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); #else SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); #endif @@ -7279,7 +7279,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); #if SIZEOF_VOID_P == 8 if (td->sp [-1].type == STACK_TYPE_I8) - interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); #endif interp_add_ins (td, MINT_LOCALLOC); if (td->sp != td->stack + 1) @@ -7793,21 +7793,18 @@ interp_local_deadce (TransformData *td) #define INTERP_FOLD_UNOP(opcode,val_type,field,op) \ case opcode: \ - g_assert (val->type == val_type); \ result.type = val_type; \ result.field = op val->field; \ break; #define INTERP_FOLD_CONV(opcode,val_type_dst,field_dst,val_type_src,field_src,cast_type) \ case opcode: \ - g_assert (val->type == val_type_src); \ result.type = val_type_dst; \ result.field_dst = (cast_type)val->field_src; \ break; #define INTERP_FOLD_CONV_FULL(opcode,val_type_dst,field_dst,val_type_src,field_src,cast_type,cond) \ case opcode: \ - g_assert (val->type == val_type_src); \ if (!(cond)) return ins; \ result.type = val_type_dst; \ result.field_dst = (cast_type)val->field_src; \ @@ -7854,9 +7851,6 @@ interp_fold_unop (TransformData *td, LocalValue *local_defs, InterpInst *ins) INTERP_FOLD_CONV (MINT_CONV_U2_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, guint16); INTERP_FOLD_CONV (MINT_CONV_U2_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, guint16); - INTERP_FOLD_CONV (MINT_CONV_I4_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint32); - INTERP_FOLD_CONV (MINT_CONV_U4_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint32); - INTERP_FOLD_CONV (MINT_CONV_I8_I4, LOCAL_VALUE_I8, l, LOCAL_VALUE_I4, i, gint32); INTERP_FOLD_CONV (MINT_CONV_I8_U4, LOCAL_VALUE_I8, l, LOCAL_VALUE_I4, i, guint32); @@ -7913,7 +7907,6 @@ interp_fold_unop (TransformData *td, LocalValue *local_defs, InterpInst *ins) #define INTERP_FOLD_UNOP_BR(_opcode,_local_type,_cond) \ case _opcode: \ - g_assert (val->type == _local_type); \ if (_cond) { \ ins->opcode = MINT_BR_S; \ if (cbb->next_bb != ins->info.target_bb) \ @@ -7960,14 +7953,12 @@ interp_fold_unop_cond_br (TransformData *td, InterpBasicBlock *cbb, LocalValue * #define INTERP_FOLD_BINOP(opcode,local_type,field,op) \ case opcode: \ - g_assert (val1->type == local_type && val2->type == local_type); \ result.type = local_type; \ result.field = val1->field op val2->field; \ break; #define INTERP_FOLD_BINOP_FULL(opcode,local_type,field,op,cast_type,cond) \ case opcode: \ - g_assert (val1->type == local_type && val2->type == local_type); \ if (!(cond)) return ins; \ result.type = local_type; \ result.field = (cast_type)val1->field op (cast_type)val2->field; \ @@ -7975,14 +7966,12 @@ interp_fold_unop_cond_br (TransformData *td, InterpBasicBlock *cbb, LocalValue * #define INTERP_FOLD_SHIFTOP(opcode,local_type,field,shift_op,cast_type) \ case opcode: \ - g_assert (val2->type == LOCAL_VALUE_I4); \ result.type = local_type; \ result.field = (cast_type)val1->field shift_op val2->i; \ break; #define INTERP_FOLD_RELOP(opcode,local_type,field,relop,cast_type) \ case opcode: \ - g_assert (val1->type == local_type && val2->type == local_type); \ result.type = LOCAL_VALUE_I4; \ result.i = (cast_type) val1->field relop (cast_type) val2->field; \ break; @@ -8096,8 +8085,6 @@ interp_fold_binop (TransformData *td, LocalValue *local_defs, InterpInst *ins) // merging quickly find the MINT_BR_S opcode. #define INTERP_FOLD_BINOP_BR(_opcode,_local_type,_cond) \ case _opcode: \ - g_assert (val1->type == _local_type); \ - g_assert (val2->type == _local_type); \ if (_cond) { \ ins->opcode = MINT_BR_S; \ if (cbb->next_bb != ins->info.target_bb) \