+#define MONO_EMIT_NEW_X86_COMPARE_MEMBASE_REG(cfg,basereg,offset,operand) do { \
+ MonoInst *inst; \
+ inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ inst->opcode = OP_X86_COMPARE_MEMBASE_REG; \
+ inst->inst_basereg = basereg; \
+ inst->inst_offset = offset; \
+ inst->sreg2 = operand; \
+ mono_bblock_add_inst (cfg->cbb, inst); \
+ } while (0)
+
+#define MONO_EMIT_NEW_X86_COMPARE_MEMBASE_IMM(cfg,basereg,offset,operand) do { \
+ MonoInst *inst; \
+ inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ inst->opcode = OP_X86_COMPARE_MEMBASE_IMM; \
+ inst->inst_basereg = basereg; \
+ inst->inst_offset = offset; \
+ inst->inst_imm = operand; \
+ mono_bblock_add_inst (cfg->cbb, inst); \
+ } while (0)
+
+/* override the arch independant versions with fast x86 versions */
+
+#undef MONO_EMIT_BOUNDS_CHECK
+#undef MONO_EMIT_BOUNDS_CHECK_IMM
+
+#define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
+ if (! (state->tree->flags & MONO_INST_NORANGECHECK)) { \
+ MONO_EMIT_NEW_X86_COMPARE_MEMBASE_REG (cfg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field), index_reg); \
+ MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
+ } \
+ } while (0)
+
+#define MONO_EMIT_BOUNDS_CHECK_IMM(cfg, array_reg, array_type, array_length_field, index_imm) do { \
+ if (! (state->tree->flags & MONO_INST_NORANGECHECK)) { \
+ MONO_EMIT_NEW_X86_COMPARE_MEMBASE_IMM (cfg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field), index_imm); \
+ MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
+ } \
+ } while (0)
+
+int call_reg_to_call_membase (int opcode);
+
%%
#
# (C) 2002 Ximian, Inc.
#
+stmt: OP_START_HANDLER {
+ MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
+ MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, spvar->inst_basereg, spvar->inst_offset, X86_ESP);
+}
+
+stmt: CEE_ENDFINALLY {
+ MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
+ MONO_EMIT_NEW_LOAD_MEMBASE (s, X86_ESP, spvar->inst_basereg, spvar->inst_offset);
+ tree->opcode = CEE_RET;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+stmt: OP_ENDFILTER (reg) {
+ MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
+ MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->left->reg1);
+ MONO_EMIT_NEW_LOAD_MEMBASE (s, X86_ESP, spvar->inst_basereg, spvar->inst_offset);
+ tree->opcode = CEE_RET;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
stmt: CEE_STIND_I8 (OP_REGVAR, lreg) {
/* this should only happen for methods returning a long */
MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->right->reg1);
MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
}
-cflags: OP_COMPARE (CEE_LDIND_I4 (base), reg) {
+cflags: OP_COMPARE (CEE_LDIND_REF (base), reg),
+cflags: OP_COMPARE (CEE_LDIND_I (base), reg),
+cflags: OP_COMPARE (CEE_LDIND_I4 (base), reg),
+cflags: OP_COMPARE (CEE_LDIND_U4 (base), reg) {
tree->opcode = OP_X86_COMPARE_MEMBASE_REG;
tree->inst_basereg = state->left->left->tree->inst_basereg;
tree->inst_offset = state->left->left->tree->inst_offset;
mono_bblock_add_inst (s->cbb, tree);
}
-cflags: OP_COMPARE (CEE_LDIND_I4 (base), OP_ICONST) {
+cflags: OP_COMPARE (CEE_LDIND_REF (base), CEE_LDIND_REF (OP_REGVAR)),
+cflags: OP_COMPARE (CEE_LDIND_I (base), CEE_LDIND_REF (OP_REGVAR)),
+cflags: OP_COMPARE (CEE_LDIND_I4 (base), CEE_LDIND_REF (OP_REGVAR)),
+cflags: OP_COMPARE (CEE_LDIND_U4 (base), CEE_LDIND_REF (OP_REGVAR)) {
+ tree->opcode = OP_X86_COMPARE_MEMBASE_REG;
+ tree->inst_basereg = state->left->left->tree->inst_basereg;
+ tree->inst_offset = state->left->left->tree->inst_offset;
+ tree->sreg2 = state->right->left->tree->dreg;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+cflags: OP_COMPARE (CEE_LDIND_REF (base), OP_ICONST),
+cflags: OP_COMPARE (CEE_LDIND_I (base), OP_ICONST),
+cflags: OP_COMPARE (CEE_LDIND_I4 (base), OP_ICONST),
+cflags: OP_COMPARE (CEE_LDIND_U4 (base), OP_ICONST) {
tree->opcode = OP_X86_COMPARE_MEMBASE_IMM;
tree->inst_basereg = state->left->left->tree->inst_basereg;
tree->inst_offset = state->left->left->tree->inst_offset;
mono_bblock_add_inst (s->cbb, tree);
}
-cflags: OP_COMPARE (reg, CEE_LDIND_I4 (base)) {
+
+cflags: OP_COMPARE (CEE_LDIND_REF (OP_ICONST), OP_ICONST),
+cflags: OP_COMPARE (CEE_LDIND_I (OP_ICONST), OP_ICONST),
+cflags: OP_COMPARE (CEE_LDIND_I4 (OP_ICONST), OP_ICONST),
+cflags: OP_COMPARE (CEE_LDIND_U4 (OP_ICONST), OP_ICONST) {
+ tree->opcode = OP_X86_COMPARE_MEM_IMM;
+ tree->inst_offset = state->left->left->tree->inst_c0;
+ tree->inst_imm = state->right->tree->inst_c0;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+cflags: OP_COMPARE (reg, CEE_LDIND_REF (base)),
+cflags: OP_COMPARE (reg, CEE_LDIND_I (base)),
+cflags: OP_COMPARE (reg, CEE_LDIND_I4 (base)),
+cflags: OP_COMPARE (reg, CEE_LDIND_U4 (base)) {
tree->opcode = OP_X86_COMPARE_REG_MEMBASE;
tree->sreg2 = state->right->left->tree->inst_basereg;
tree->inst_offset = state->right->left->tree->inst_offset;
mono_bblock_add_inst (s->cbb, tree);
}
+cflags: OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), CEE_LDIND_REF (base)),
+cflags: OP_COMPARE (CEE_LDIND_I (OP_REGVAR), CEE_LDIND_I (base)),
+cflags: OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), CEE_LDIND_I4 (base)),
+cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), CEE_LDIND_U4 (base)) {
+ tree->opcode = OP_X86_COMPARE_REG_MEMBASE;
+ tree->sreg2 = state->right->left->tree->inst_basereg;
+ tree->inst_offset = state->right->left->tree->inst_offset;
+ tree->sreg1 = state->left->left->tree->dreg;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+cflags : OP_CEQ (OP_COMPARE (OP_CEQ (cflags), OP_ICONST)) {
+ tree->opcode = OP_CNE;
+ tree->dreg = state->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+} cost {
+ MBCOND (!state->left->right->tree->inst_c0);
+ return 1;
+}
+
+stmt: CEE_STIND_I1 (base, OP_CEQ (OP_COMPARE (OP_CEQ (cflags), OP_ICONST))) {
+ tree->opcode = OP_X86_SETNE_MEMBASE;
+ tree->inst_offset = state->left->tree->inst_offset;
+ tree->inst_basereg = state->left->tree->inst_basereg;
+ mono_bblock_add_inst (s->cbb, tree);
+} cost {
+ MBCOND (!state->right->left->right->tree->inst_c0);
+ return 1;
+}
+
stmt: CEE_STIND_I1 (base, OP_CEQ (cflags)) {
tree->opcode = OP_X86_SETEQ_MEMBASE;
tree->inst_offset = state->left->tree->inst_offset;
if (tree->flags & MONO_INST_INIT) {
/* microcoded in mini-x86.c */
tree->sreg1 = mono_regstate_next_int (s->rs);
+ tree->dreg = state->reg1;
MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
mono_bblock_add_inst (s->cbb, tree);
} else {
- MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, state->left->tree->inst_c0);
+ guint32 size = state->left->tree->inst_c0;
+ size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
+ MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, size);
MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, X86_ESP);
}
}
reg: OP_LOCALLOC (reg) {
+ tree->sreg1 = state->left->tree->dreg;
+ tree->dreg = state->reg1;
mono_bblock_add_inst (s->cbb, tree);
}
stmt: OP_SETRET (reg) {
- tree->opcode = OP_MOVE;
- tree->sreg1 = state->left->reg1;
- tree->dreg = X86_EAX;
- mono_bblock_add_inst (s->cbb, tree);
+ MONO_EMIT_UNALU (s, tree, OP_MOVE, X86_EAX, state->left->reg1);
}
stmt: OP_SETRET (lreg) {
MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->left->reg2);
- tree->opcode = OP_MOVE;
- tree->sreg1 = state->left->reg1;
- tree->dreg = X86_EAX;
- mono_bblock_add_inst (s->cbb, tree);
+ MONO_EMIT_UNALU (s, tree, OP_MOVE, X86_EAX, state->left->reg1);
}
-stmt: OP_SETRET (CEE_LDIND_REF (OP_REGVAR)) {
- tree->opcode = OP_MOVE;
- tree->sreg1 = state->left->left->tree->dreg;
- tree->dreg = X86_EAX;
- mono_bblock_add_inst (s->cbb, tree);
+stmt: OP_SETRET (CEE_LDIND_REF (OP_REGVAR)),
+stmt: OP_SETRET (CEE_LDIND_I (OP_REGVAR)),
+stmt: OP_SETRET (CEE_LDIND_I4 (OP_REGVAR)),
+stmt: OP_SETRET (CEE_LDIND_U4 (OP_REGVAR)) {
+ MONO_EMIT_UNALU (s, tree, OP_MOVE, X86_EAX, state->left->left->tree->dreg);
}
stmt: OP_SETRET (freg) {
mono_bblock_add_inst (s->cbb, tree);
}
-stmt: OP_OUTARG (reg) {
- tree->opcode = OP_X86_PUSH;
- tree->sreg1 = state->left->reg1;
- mono_bblock_add_inst (s->cbb, tree);
+stmt: OP_SETRET (i8con) {
+ MONO_EMIT_NEW_ICONST (s, X86_EAX, state->left->tree->inst_ls_word);
+ MONO_EMIT_NEW_ICONST (s, X86_EDX, state->left->tree->inst_ms_word);
}
-# we need to reduce this code duplication with some burg syntax extension
-stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
- tree->opcode = OP_X86_PUSH;
- tree->sreg1 = state->left->left->tree->dreg;
- mono_bblock_add_inst (s->cbb, tree);
-}
-
-stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)) {
+stmt: OP_OUTARG (reg) {
tree->opcode = OP_X86_PUSH;
- tree->sreg1 = state->left->left->tree->dreg;
+ tree->sreg1 = state->left->reg1;
mono_bblock_add_inst (s->cbb, tree);
}
-stmt: OP_OUTARG (CEE_LDIND_U4 (OP_REGVAR)) {
+stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)),
+stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)),
+stmt: OP_OUTARG (CEE_LDIND_U4 (OP_REGVAR)),
+stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)) {
tree->opcode = OP_X86_PUSH;
tree->sreg1 = state->left->left->tree->dreg;
mono_bblock_add_inst (s->cbb, tree);
}
-stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)) {
- tree->opcode = OP_X86_PUSH;
- tree->sreg1 = state->left->left->tree->dreg;
- mono_bblock_add_inst (s->cbb, tree);
+stmt: OP_OUTARG (OP_GOT_ENTRY (CEE_LDIND_I (OP_REGVAR), OP_PATCH_INFO)) {
+ MonoInst *ins;
+ ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
+ ins->opcode = OP_X86_PUSH_GOT_ENTRY;
+ ins->inst_right = state->left->right->tree;
+ ins->inst_basereg = state->left->left->left->tree->dreg;
+ mono_bblock_add_inst (s->cbb, ins);
}
stmt: OP_OUTARG (lreg) {
mono_bblock_add_inst (s->cbb, tree);
}
-stmt: OP_OUTARG (CEE_LDIND_I4 (base)) {
- tree->opcode = OP_X86_PUSH_MEMBASE;
- tree->inst_basereg = state->left->left->tree->inst_basereg;
- tree->inst_offset = state->left->left->tree->inst_offset;
- mono_bblock_add_inst (s->cbb, tree);
-}
-
-stmt: OP_OUTARG (CEE_LDIND_U4 (base)) {
- tree->opcode = OP_X86_PUSH_MEMBASE;
- tree->inst_basereg = state->left->left->tree->inst_basereg;
- tree->inst_offset = state->left->left->tree->inst_offset;
- mono_bblock_add_inst (s->cbb, tree);
-}
+stmt: OP_OUTARG (i8con) {
+ MonoInst *ins;
+ ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
+ ins->opcode = OP_X86_PUSH_IMM;
+ ins->inst_imm = state->left->tree->inst_ms_word;
+ mono_bblock_add_inst (s->cbb, ins);
-stmt: OP_OUTARG (CEE_LDIND_I (base)) {
- tree->opcode = OP_X86_PUSH_MEMBASE;
- tree->inst_basereg = state->left->left->tree->inst_basereg;
- tree->inst_offset = state->left->left->tree->inst_offset;
+ tree->opcode = OP_X86_PUSH_IMM;
+ tree->inst_imm = state->left->tree->inst_ls_word;
mono_bblock_add_inst (s->cbb, tree);
}
+stmt: OP_OUTARG (CEE_LDIND_I4 (base)),
+stmt: OP_OUTARG (CEE_LDIND_U4 (base)),
+stmt: OP_OUTARG (CEE_LDIND_I (base)),
stmt: OP_OUTARG (CEE_LDIND_REF (base)) {
tree->opcode = OP_X86_PUSH_MEMBASE;
tree->inst_basereg = state->left->left->tree->inst_basereg;
mono_bblock_add_inst (s->cbb, tree);
}
-stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
- tree->opcode = OP_X86_PUSH;
- tree->sreg1 = state->left->left->tree->dreg;
- mono_bblock_add_inst (s->cbb, tree);
-}
-
stmt: OP_OUTARG (CEE_LDOBJ (reg)) {
tree->opcode = OP_X86_PUSH;
tree->sreg1 = state->left->reg1;
stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
MonoInst *vt = state->left->left->tree;
//g_print ("vt size: %d at R%d + %d\n", tree->inst_imm, vt->inst_basereg, vt->inst_offset);
+
+ if (!tree->inst_imm)
+ return;
+
if (tree->inst_imm <= 4) {
tree->opcode = OP_X86_PUSH_MEMBASE;
tree->inst_basereg = vt->inst_basereg;
tree->inst_offset = vt->inst_offset;
mono_bblock_add_inst (s->cbb, tree);
+ } else if (tree->inst_imm <= 20) {
+ int sz = tree->inst_imm;
+ sz += 3;
+ sz &= ~3;
+ MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, sz);
+ mini_emit_memcpy (s, X86_ESP, 0, vt->inst_basereg, vt->inst_offset, tree->inst_imm, 0);
} else {
tree->opcode = OP_X86_PUSH_OBJ;
tree->inst_basereg = vt->inst_basereg;
mono_bblock_add_inst (s->cbb, tree);
}
+stmt: OP_OUTARG_VT (reg) {
+ tree->opcode = OP_X86_PUSH;
+ tree->sreg1 = state->left->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+reg: OP_LDADDR (OP_REGOFFSET),
+reg: CEE_LDOBJ (OP_REGOFFSET) {
+ if (state->left->tree->inst_offset) {
+ tree->opcode = OP_X86_LEA_MEMBASE;
+ tree->inst_imm = state->left->tree->inst_offset;
+ } else
+ tree->opcode = OP_MOVE;
+
+ tree->sreg1 = state->left->tree->inst_basereg;
+ tree->dreg = state->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
reg: CEE_LDELEMA (reg, reg) "15" {
- int length_reg = mono_regstate_next_int (s->rs);
guint32 size = mono_class_array_element_size (tree->klass);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, length_reg,
- state->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length));
- MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, length_reg, state->right->reg1);
- MONO_EMIT_NEW_COND_EXC (s, LE_UN, "IndexOutOfRangeException");
+ MONO_EMIT_BOUNDS_CHECK (s, state->left->reg1, MonoArray, max_length, state->right->reg1);
if (size == 1 || size == 2 || size == 4 || size == 8) {
static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
mono_bblock_add_inst (s->cbb, tree);
}
+stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
int con = state->right->right->tree->inst_c0;
int dreg = state->left->tree->dreg;
MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);
}
+# The XOR rule
+stmt: CEE_STIND_I4 (OP_REGVAR, OP_ICONST),
+stmt: CEE_STIND_I2 (OP_REGVAR, OP_ICONST),
+stmt: CEE_STIND_I1 (OP_REGVAR, OP_ICONST),
+stmt: CEE_STIND_REF (OP_REGVAR, OP_ICONST),
+stmt: CEE_STIND_I (OP_REGVAR, OP_ICONST) {
+ int r = state->left->tree->dreg;
+ MONO_EMIT_BIALU (s, tree, CEE_XOR, r, r, r);
+} cost {
+ MBCOND (!state->right->tree->inst_c0);
+
+ return 0;
+}
+
# on x86, fp compare overwrites EAX, so we must
# either improve the local register allocator or
# emit coarse opcodes which saves EAX for us.
MONO_EMIT_UNALU (s, tree, OP_X86_FPOP, -1, state->left->reg1);
}
+# override the rules in inssel-float.brg that work for machines with FP registers
+
+freg: OP_FCONV_TO_R8 (freg) "0" {
+ /* nothing to do */
+}
+
+freg: OP_FCONV_TO_R4 (freg) "0" {
+ /* fixme: nothing to do ??*/
+}
+
+reg: CEE_ADD(reg, CEE_LDIND_I4 (base)) {
+ MonoInst *base = state->right->left->tree;
+
+ tree->dreg = state->reg1;
+ tree->sreg1 = state->left->reg1;
+ tree->sreg2 = base->inst_basereg;
+ tree->inst_offset = base->inst_offset;
+ tree->opcode = OP_X86_ADD_MEMBASE;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+reg: CEE_SUB(reg, CEE_LDIND_I4 (base)) {
+ MonoInst *base = state->right->left->tree;
+
+ tree->dreg = state->reg1;
+ tree->sreg1 = state->left->reg1;
+ tree->sreg2 = base->inst_basereg;
+ tree->inst_offset = base->inst_offset;
+ tree->opcode = OP_X86_SUB_MEMBASE;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+reg: CEE_MUL(reg, CEE_LDIND_I4 (base)) {
+ MonoInst *base = state->right->left->tree;
+
+ tree->dreg = state->reg1;
+ tree->sreg1 = state->left->reg1;
+ tree->sreg2 = base->inst_basereg;
+ tree->inst_offset = base->inst_offset;
+ tree->opcode = OP_X86_MUL_MEMBASE;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+lreg: OP_LSHL (lreg, reg) "0" {
+ MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
+}
+
+lreg: OP_LSHL (lreg, OP_ICONST) "0" {
+ MONO_EMIT_BIALU_IMM (s, tree, OP_LSHL_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+lreg: OP_LSHR (lreg, reg) "0" {
+ MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
+}
+
+lreg: OP_LSHR (lreg, OP_ICONST) "0" {
+ MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+lreg: OP_LSHR_UN (lreg, reg) "0" {
+ MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
+}
+
+lreg: OP_LSHR_UN (lreg, OP_ICONST) "0" {
+ MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_UN_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: OP_ATOMIC_ADD_NEW_I4 (base, reg),
+reg: OP_ATOMIC_ADD_I4 (base, reg) {
+ tree->opcode = tree->opcode;
+ tree->inst_basereg = state->left->tree->inst_basereg;
+ tree->inst_offset = state->left->tree->inst_offset;
+ tree->dreg = state->reg1;
+ tree->sreg2 = state->right->reg1;
+
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+reg: OP_ATOMIC_EXCHANGE_I4 (base, reg) {
+ tree->opcode = OP_ATOMIC_EXCHANGE_I4;
+ tree->dreg = state->reg1;
+ tree->sreg2 = state->right->reg1;
+ tree->inst_basereg = state->left->tree->inst_basereg;
+ tree->inst_offset = state->left->tree->inst_offset;
+
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+# Optimized call instructions
+# mono_arch_patch_delegate_trampoline depends on these
+reg: OP_CALL_REG (CEE_LDIND_I (base)),
+freg: OP_FCALL_REG (CEE_LDIND_I (base)),
+reg: OP_LCALL_REG (CEE_LDIND_I (base)) {
+ tree->opcode = call_reg_to_call_membase (tree->opcode);
+ tree->inst_basereg = state->left->left->tree->inst_basereg;
+ tree->inst_offset = state->left->left->tree->inst_offset;
+ tree->dreg = state->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+lreg: OP_LCALL_REG (CEE_LDIND_I (base)) {
+ tree->opcode = call_reg_to_call_membase (tree->opcode);
+ tree->inst_basereg = state->left->left->tree->inst_basereg;
+ tree->inst_offset = state->left->left->tree->inst_offset;
+ tree->dreg = state->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+stmt: OP_VOIDCALL_REG (CEE_LDIND_I (base)) {
+ tree->opcode = call_reg_to_call_membase (tree->opcode);
+ tree->inst_basereg = state->left->left->tree->inst_basereg;
+ tree->inst_offset = state->left->left->tree->inst_offset;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+stmt: OP_VCALL_REG (CEE_LDIND_I (base), reg) {
+ mono_arch_emit_this_vret_args (s, (MonoCallInst*)tree, -1, -1, state->right->reg1);
+
+ tree->opcode = call_reg_to_call_membase (tree->opcode);
+ tree->inst_basereg = state->left->left->tree->inst_basereg;
+ tree->inst_offset = state->left->left->tree->inst_offset;
+ tree->dreg = state->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+# Optimized ldind(reg) rules
+reg: CEE_LDIND_REF (OP_REGVAR),
+reg: CEE_LDIND_I (OP_REGVAR),
+reg: CEE_LDIND_I4 (OP_REGVAR),
+reg: CEE_LDIND_U4 (OP_REGVAR) "0" {
+ state->reg1 = state->left->tree->dreg;
+ tree->dreg = state->reg1;
+}
+
%%
+
+int
+call_reg_to_call_membase (int opcode)
+{
+ switch (opcode) {
+ case OP_CALL_REG:
+ return OP_CALL_MEMBASE;
+ case OP_FCALL_REG:
+ return OP_FCALL_MEMBASE;
+ case OP_VCALL_REG:
+ return OP_VCALL_MEMBASE;
+ case OP_LCALL_REG:
+ return OP_LCALL_MEMBASE;
+ case OP_VOIDCALL_REG:
+ return OP_VOIDCALL_MEMBASE;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return -1;
+}