2004-06-10 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / mini / inssel-x86.brg
index 19495c6d0083357f93a4c07510a1540257de2865..b1f1cf67c77c49610fdc68c8ca4931fbace2a243 100644 (file)
@@ -1,3 +1,43 @@
+#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)
+
+
 %%
 
 #
 # (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);
@@ -30,16 +90,20 @@ freg: OP_LCONV_TO_R8 (lreg) {
        tree->inst_basereg = X86_ESP;
        tree->inst_offset = 0;
        mono_bblock_add_inst (s->cbb, tree);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
 }
 
 freg: OP_LCONV_TO_R4 (lreg) {
+       MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
        MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
-       tree->opcode = OP_X86_FP_LOAD_I4;
+       tree->opcode = OP_X86_FP_LOAD_I8;
        tree->inst_basereg = X86_ESP;
        tree->inst_offset = 0;
        mono_bblock_add_inst (s->cbb, tree);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
+       /* change precision */
+       MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, X86_ESP, 0, state->reg1);
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, state->reg1, X86_ESP, 0);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
 }
 
 freg: CEE_CONV_R_UN (reg) {
@@ -49,7 +113,7 @@ freg: CEE_CONV_R_UN (reg) {
        tree->inst_basereg = X86_ESP;
        tree->inst_offset = 0;
        mono_bblock_add_inst (s->cbb, tree);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
 }
 
 cflags: OP_COMPARE (CEE_LDIND_I4 (base), reg) {
@@ -76,6 +140,13 @@ cflags: OP_COMPARE (reg, CEE_LDIND_I4 (base)) {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+stmt: CEE_STIND_I1 (base, OP_CEQ (cflags)) {
+       tree->opcode = OP_X86_SETEQ_MEMBASE;
+       tree->inst_offset = state->left->tree->inst_offset;
+       tree->inst_basereg = state->left->tree->inst_basereg;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
 reg: OP_LOCALLOC (OP_ICONST) {
        if (tree->flags & MONO_INST_INIT) {
                /* microcoded in mini-x86.c */
@@ -89,6 +160,7 @@ reg: OP_LOCALLOC (OP_ICONST) {
 }
 
 reg: OP_LOCALLOC (reg) {
+       tree->sreg1 = state->left->tree->dreg;
        mono_bblock_add_inst (s->cbb, tree);
 }
 
@@ -253,11 +325,21 @@ stmt: OP_OUTARG_R8 (freg) {
 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;
@@ -272,14 +354,44 @@ stmt: OP_OUTARG_VT (OP_ICONST) {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+stmt: OP_OUTARG_VT (reg) {
+       tree->opcode = OP_X86_PUSH;
+       tree->sreg1 = state->left->tree->dreg;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+reg: OP_LDADDR (OP_REGOFFSET) "1" {
+       if (state->left->tree->inst_offset) {
+               tree->opcode = OP_X86_LEA_MEMBASE;
+               tree->sreg1 = state->left->tree->inst_basereg;
+               tree->inst_imm = state->left->tree->inst_offset;
+               tree->dreg = state->reg1;
+       } 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_LDOBJ (OP_REGOFFSET) "1" {
+       if (state->left->tree->inst_offset) {
+               tree->opcode = OP_X86_LEA_MEMBASE;
+               tree->sreg1 = state->left->tree->inst_basereg;
+               tree->inst_imm = state->left->tree->inst_offset;
+               tree->dreg = state->reg1;
+       } 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 };
@@ -383,6 +495,7 @@ stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
        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;
@@ -407,6 +520,10 @@ stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+reg: CEE_LDIND_I2 (OP_REGVAR) {
+       MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);
+}
+
 # on x86, fp compare overwrites EAX, so we must
 # either improve the local register allocator or
 # emit coarse opcodes which saves EAX for us.
@@ -494,4 +611,70 @@ stmt: CEE_POP (freg) "0" {
        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);
+}
 %%