Skip to content

Commit

Permalink
[mono][interp] Add new ldind super instruction
Browse files Browse the repository at this point in the history
These new instructions can apply addition and multiplication with constant to the offset var.
  • Loading branch information
BrzVlad committed Dec 12, 2022
1 parent 3558b6d commit 32b8723
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4910,6 +4910,41 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
#endif
MINT_IN_BREAK;

#define LDIND_OFFSET_ADD_MUL(datatype,casttype,unaligned) do { \
MONO_DISABLE_WARNING(4127) \
gpointer ptr = LOCAL_VAR (ip [2], gpointer); \
NULL_CHECK (ptr); \
ptr = (char*)ptr + (LOCAL_VAR (ip [3], mono_i) + (gint16)ip [4]) * (gint16)ip [5]; \
if (unaligned && ((gsize)ptr % SIZEOF_VOID_P)) \
memcpy (locals + ip [1], ptr, sizeof (datatype)); \
else \
LOCAL_VAR (ip [1], datatype) = *(casttype*)ptr; \
ip += 6; \
MONO_RESTORE_WARNING \
} while (0)
MINT_IN_CASE(MINT_LDIND_OFFSET_ADD_MUL_IMM_I1)
LDIND_OFFSET_ADD_MUL(gint32, gint8, FALSE);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_OFFSET_ADD_MUL_IMM_U1)
LDIND_OFFSET_ADD_MUL(gint32, guint8, FALSE);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_OFFSET_ADD_MUL_IMM_I2)
LDIND_OFFSET_ADD_MUL(gint32, gint16, FALSE);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_OFFSET_ADD_MUL_IMM_U2)
LDIND_OFFSET_ADD_MUL(gint32, guint16, FALSE);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_OFFSET_ADD_MUL_IMM_I4)
LDIND_OFFSET_ADD_MUL(gint32, gint32, FALSE);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_OFFSET_ADD_MUL_IMM_I8)
#ifdef NO_UNALIGNED_ACCESS
LDIND_OFFSET_ADD_MUL(gint64, gint64, TRUE);
#else
LDIND_OFFSET_ADD_MUL(gint64, gint64, FALSE);
#endif
MINT_IN_BREAK;

#define LDIND_OFFSET_IMM(datatype,casttype,unaligned) do { \
MONO_DISABLE_WARNING(4127) \
gpointer ptr = LOCAL_VAR (ip [2], gpointer); \
Expand Down
7 changes: 7 additions & 0 deletions src/mono/mono/mini/interp/mintops.def
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ 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_LDIND_OFFSET_ADD_MUL_IMM_I1, "ldind_off_add_mul_imm.i1", 6, 1, 2, MintOpTwoShorts)
OPDEF(MINT_LDIND_OFFSET_ADD_MUL_IMM_U1, "ldind_off_add_mul_imm.u1", 6, 1, 2, MintOpTwoShorts)
OPDEF(MINT_LDIND_OFFSET_ADD_MUL_IMM_I2, "ldind_off_add_mul_imm.i2", 6, 1, 2, MintOpTwoShorts)
OPDEF(MINT_LDIND_OFFSET_ADD_MUL_IMM_U2, "ldind_off_add_mul_imm.u2", 6, 1, 2, MintOpTwoShorts)
OPDEF(MINT_LDIND_OFFSET_ADD_MUL_IMM_I4, "ldind_off_add_mul_imm.i4", 6, 1, 2, MintOpTwoShorts)
OPDEF(MINT_LDIND_OFFSET_ADD_MUL_IMM_I8, "ldind_off_add_mul_imm.i8", 6, 1, 2, MintOpTwoShorts)

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)
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/interp/mintops.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ typedef enum {
#define MINT_IS_LDIND(op) ((op) >= MINT_LDIND_I1 && (op) <= MINT_LDIND_R8)
#define MINT_IS_STIND_INT(op) ((op) >= MINT_STIND_I1 && (op) <= MINT_STIND_I8)
#define MINT_IS_STIND(op) ((op) >= MINT_STIND_I1 && (op) <= MINT_STIND_REF)
#define MINT_IS_LDIND_OFFSET(op) ((op) >= MINT_LDIND_OFFSET_I1 && (op) <= MINT_LDIND_OFFSET_I8)

// TODO Add more
#define MINT_NO_SIDE_EFFECTS(op) (MINT_IS_MOV (op) || MINT_IS_LDC_I4 (op) || MINT_IS_LDC_I8 (op) || op == MINT_MONO_LDPTR)
Expand Down
41 changes: 41 additions & 0 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,17 @@ MonoInterpStats mono_interp_stats;
#define MINT_STIND_I MINT_STIND_I8
#define MINT_LDELEM_I MINT_LDELEM_I8
#define MINT_STELEM_I MINT_STELEM_I8
#define MINT_MUL_P_IMM MINT_MUL_I8_IMM
#define MINT_ADD_MUL_P_IMM MINT_ADD_MUL_I8_IMM
#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
#define MINT_LDELEM_I MINT_LDELEM_I4
#define MINT_STELEM_I MINT_STELEM_I4
#define MINT_MUL_P_IMM MINT_MUL_I4_IMM
#define MINT_ADD_MUL_P_IMM MINT_ADD_MUL_I4_IMM
#endif

static const char *stack_type_string [] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
Expand Down Expand Up @@ -9654,6 +9658,43 @@ interp_super_instructions (TransformData *td)
}
}
}
} else if (MINT_IS_LDIND_OFFSET (opcode)) {
int sreg_off = ins->sregs [1];
InterpInst *def = td->locals [sreg_off].def;
if (def != NULL && td->local_ref_count [sreg_off] == 1) {
if (def->opcode == MINT_MUL_P_IMM || def->opcode == MINT_ADD_P_IMM || def->opcode == MINT_ADD_MUL_P_IMM) {
int ldind_offset_op = MINT_LDIND_OFFSET_ADD_MUL_IMM_I1 + (opcode - MINT_LDIND_OFFSET_I1);
InterpInst *new_inst = interp_insert_ins (td, ins, ldind_offset_op);
new_inst->dreg = ins->dreg;
new_inst->sregs [0] = ins->sregs [0]; // base
new_inst->sregs [1] = def->sregs [0]; // off

// set the add and mul immediates
switch (def->opcode) {
case MINT_ADD_P_IMM:
new_inst->data [0] = def->data [0];
new_inst->data [1] = 1;
break;
case MINT_MUL_P_IMM:
new_inst->data [0] = 0;
new_inst->data [1] = def->data [0];
break;
case MINT_ADD_MUL_P_IMM:
new_inst->data [0] = def->data [0];
new_inst->data [1] = def->data [1];
break;
}

interp_clear_ins (def);
interp_clear_ins (ins);
local_ref_count [sreg_off]--;
mono_interp_stats.super_instructions++;
if (td->verbose_level) {
g_print ("method %s:%s, superins: ", m_class_get_name (td->method->klass), td->method->name);
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;
Expand Down

0 comments on commit 32b8723

Please sign in to comment.