From 53929d630f0e6b55be049e914dfb886f1ef3a385 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Thu, 24 Oct 2019 18:05:04 +0300 Subject: [PATCH] [interp] Add super instructions for field storing (mono/mono#17525) * [interp] Add also floating versions for stloc.np * [interp] Add super instructions for stfld When storing into a field of a local or an argument (ldloc/ldarg -> random instructions that end up pushing one value -> stfld). We add this instruction to the cprop pass because the instructions that are optimized together are not consecutive and we need the stack information to be able to access the instruction that loaded the argument / local and to make sure that the local wasn't dirtied. Alternatively we could make the super instruction pass stack aware, which we should probably do if more super instruction candidates turn out to require stack state information. * [interp] Enable cprop for methods without locals We do some optimizations here that don't apply to locals. * [interp] Fix result stack type of CEE_CONV_OVF_I_UN Commit migrated from https://github.com/mono/mono/commit/b7ef7363382757c2951a7a84026d5a1baa7f0130 --- src/mono/mono/mini/interp/interp.c | 52 +++++++++++++++++++++++++++++++++++ src/mono/mono/mini/interp/mintops.def | 24 ++++++++++++++++ src/mono/mono/mini/interp/mintops.h | 1 + src/mono/mono/mini/interp/transform.c | 43 +++++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 6b37efd..95c4447 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -5096,6 +5096,56 @@ common_vcall: sp -= 2; MINT_IN_BREAK; +#define STARGFLD(datamem, fieldtype) do { \ + MonoObject *o = frame->stack_args [ip [1]].data.o; \ + NULL_CHECK (o); \ + sp--; \ + * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \ + ip += 3; \ +} while (0) + MINT_IN_CASE(MINT_STARGFLD_I1) STARGFLD(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_U1) STARGFLD(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_I2) STARGFLD(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_U2) STARGFLD(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_I4) STARGFLD(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_I8) STARGFLD(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_R4) STARGFLD(f_r4, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_R8) STARGFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_P) STARGFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARGFLD_O) { + MonoObject *o = frame->stack_args [ip [1]].data.o; + NULL_CHECK (o); + sp--; + mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o); + ip += 3; + MINT_IN_BREAK; + } + +#define STLOCFLD(datamem, fieldtype) do { \ + MonoObject *o = *(MonoObject**)(locals + ip [1]); \ + NULL_CHECK (o); \ + sp--; \ + * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \ + ip += 3; \ +} while (0) + MINT_IN_CASE(MINT_STLOCFLD_I1) STLOCFLD(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_U1) STLOCFLD(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_I2) STLOCFLD(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_U2) STLOCFLD(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_I4) STLOCFLD(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_I8) STLOCFLD(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_R4) STLOCFLD(f_r4, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_R8) STLOCFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_P) STLOCFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOCFLD_O) { + MonoObject *o = *(MonoObject**)(locals + ip [1]); + NULL_CHECK (o); + sp--; + mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o); + ip += 3; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDSFLDA) { MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; INIT_VTABLE (vtable); @@ -6415,6 +6465,8 @@ common_vcall: MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOC_NP_I8) STLOC_NP(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_NP_R4) STLOC_NP(f_r4, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_NP_R8) STLOC_NP(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOC_VT) { diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 81a01d8..ef83487 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -133,6 +133,28 @@ OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 2, Pop2, Push0, MintOpUShor OPDEF(MINT_STRMFLD, "strmfld", 2, Pop2, Push0, MintOpFieldToken) OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 2, Pop2, Push0, MintOpUShortInt) +OPDEF(MINT_STARGFLD_I1, "stargfld.i1", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_U1, "stargfld.u1", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_I2, "stargfld.i2", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_U2, "stargfld.u2", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_I4, "stargfld.i4", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_I8, "stargfld.i8", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_R4, "stargfld.r4", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_R8, "stargfld.r8", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_O, "stargfld.o", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STARGFLD_P, "stargfld.p", 3, Pop1, Push0, MintOpTwoShorts) + +OPDEF(MINT_STLOCFLD_I1, "stlocfld.i1", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_U1, "stlocfld.u1", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_I2, "stlocfld.i2", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_U2, "stlocfld.u2", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_I4, "stlocfld.i4", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_I8, "stlocfld.i8", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_R4, "stlocfld.r4", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_R8, "stlocfld.r8", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_O, "stlocfld.o", 3, Pop1, Push0, MintOpTwoShorts) +OPDEF(MINT_STLOCFLD_P, "stlocfld.p", 3, Pop1, Push0, MintOpTwoShorts) + OPDEF(MINT_LDTSFLD_I1, "ldtsfld.i1", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDTSFLD_U1, "ldtsfld.u1", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDTSFLD_I2, "ldtsfld.i2", 3, Pop0, Push1, MintOpInt) @@ -210,6 +232,8 @@ OPDEF(MINT_STLOC_VT, "stloc.vt", 4, Pop1, Push0, MintOpShortAndInt) OPDEF(MINT_STLOC_NP_I4, "stloc.np.i4", 2, Pop0, Push0, MintOpUShortInt) OPDEF(MINT_STLOC_NP_I8, "stloc.np.i8", 2, Pop0, Push0, MintOpUShortInt) +OPDEF(MINT_STLOC_NP_R4, "stloc.np.R4", 2, Pop0, Push0, MintOpUShortInt) +OPDEF(MINT_STLOC_NP_R8, "stloc.np.R8", 2, Pop0, Push0, MintOpUShortInt) OPDEF(MINT_STLOC_NP_O, "stloc.np.o", 2, Pop0, Push0, MintOpUShortInt) OPDEF(MINT_MOVLOC_1, "movloc.1", 3, Pop0, Push0, MintOpTwoShorts) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index 0afec36..69c4239 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -65,6 +65,7 @@ typedef enum { #define MINT_IS_UNOP(op) ((op) >= MINT_ADD1_I4 && (op) <= MINT_CEQ0_I4) #define MINT_IS_BINOP(op) ((op) >= MINT_ADD_I4 && (op) <= MINT_CLT_UN_R8) #define MINT_IS_LDLOCFLD(op) ((op) >= MINT_LDLOCFLD_I1 && (op) <= MINT_LDLOCFLD_P) +#define MINT_IS_STLOCFLD(op) ((op) >= MINT_STLOCFLD_I1 && (op) <= MINT_STLOCFLD_P) #define MINT_IS_LOCUNOP(op) ((op) >= MINT_LOCADD1_I4 && (op) <= MINT_LOCSUB1_I8) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 7779a1aa..3cc82d2 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -4916,7 +4916,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, g_assert_not_reached (); break; } - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); + SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); ++td->ip; break; case CEE_CONV_OVF_I8_UN: @@ -6399,7 +6399,7 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in cbb->last_seq_point = seqp; } else { if (MINT_IS_LDLOC (opcode) || MINT_IS_STLOC (opcode) || MINT_IS_STLOC_NP (opcode) || opcode == MINT_LDLOCA_S || - MINT_IS_LDLOCFLD (opcode) || MINT_IS_LOCUNOP (opcode)) { + MINT_IS_LDLOCFLD (opcode) || MINT_IS_LOCUNOP (opcode) || MINT_IS_STLOCFLD (opcode)) { ins->data [0] = get_interp_local_offset (td, ins->data [0]); } else if (MINT_IS_MOVLOC (opcode)) { ins->data [0] = get_interp_local_offset (td, ins->data [0]); @@ -6791,7 +6791,7 @@ interp_local_equal (StackValue *locals, int local1, int local2) static void interp_cprop (TransformData *td) { - if (!td->max_stack_height || !td->locals_size) + if (!td->max_stack_height) return; StackContentInfo *stack = (StackContentInfo*) g_malloc (td->max_stack_height * sizeof (StackContentInfo)); StackContentInfo *stack_end = stack + td->max_stack_height; @@ -6839,6 +6839,10 @@ retry: replace_op = MINT_STLOC_NP_I4; else if (mt == MINT_TYPE_I8) replace_op = MINT_STLOC_NP_I8; + else if (mt == MINT_TYPE_R4) + replace_op = MINT_STLOC_NP_R4; + else if (mt == MINT_TYPE_R8) + replace_op = MINT_STLOC_NP_R8; else if (mt == MINT_TYPE_O || mt == MINT_TYPE_P) replace_op = MINT_STLOC_NP_O; if (replace_op) { @@ -7067,6 +7071,39 @@ retry: } else if (MINT_IS_BINOP (ins->opcode)) { ins = interp_fold_binop (td, sp, ins); sp--; + } else if (ins->opcode >= MINT_STFLD_I1 && ins->opcode <= MINT_STFLD_P && (mono_interp_opt & INTERP_OPT_SUPER_INSTRUCTIONS)) { + if (sp [-2].ins) { + InterpInst *obj_ins = sp [-2].ins; + if (obj_ins->opcode == MINT_LDLOC_O) { + int loc_index = obj_ins->data [0]; + int fld_offset = ins->data [0]; + int mt = ins->opcode - MINT_STFLD_I1; + ins = interp_insert_ins (td, ins, MINT_STLOCFLD_I1 + mt); + ins->data [0] = loc_index; + ins->data [1] = fld_offset; + interp_clear_ins (td, ins->prev); + interp_clear_ins (td, obj_ins); + mono_interp_stats.super_instructions++; + mono_interp_stats.killed_instructions++; + } else if (obj_ins->opcode == MINT_LDARG_O || obj_ins->opcode == MINT_LDARG_P0) { + int arg_index = 0; + int fld_offset = ins->data [0]; + int mt = ins->opcode - MINT_STFLD_I1; + if (obj_ins->opcode == MINT_LDARG_O) + arg_index = obj_ins->data [0]; + ins = interp_insert_ins (td, ins, MINT_STARGFLD_I1 + mt); + ins->data [0] = arg_index; + ins->data [1] = fld_offset; + interp_clear_ins (td, ins->prev); + interp_clear_ins (td, obj_ins); + mono_interp_stats.super_instructions++; + mono_interp_stats.killed_instructions++; + } + } + sp -= 2; + } else if (MINT_IS_STLOCFLD (ins->opcode)) { + local_ref_count [ins->data [0]]++; + sp--; } else { if (pop == MINT_POP_ALL) pop = sp - stack; -- 2.7.4