Merge pull request #2453 from kumpera/fix_ji_free
[mono.git] / mono / mini / local-propagation.c
index 31ed7dcd427b7adeb91285b640895c0bfa9c67c7..aa2a934f556215633115d9cce999a9b6361575d7 100644 (file)
@@ -9,8 +9,11 @@
  *   Massimiliano Mantione (massi@ximian.com)
  *
  * (C) 2006 Novell, Inc.  http://www.novell.com
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  */
 
+#include <config.h>
+#ifndef DISABLE_JIT
 
 #include <string.h>
 #include <stdio.h>
@@ -50,12 +53,13 @@ mono_local_cprop (MonoCompile *cfg)
        MonoInst **defs;
        gint32 *def_index;
        int max;
+       int filter = FILTER_IL_SEQ_POINT;
 
 restart:
 
        max = cfg->next_vreg;
-       defs = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * (cfg->next_vreg + 1));
-       def_index = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * (cfg->next_vreg + 1));
+       defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * (cfg->next_vreg + 1));
+       def_index = (gint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * (cfg->next_vreg + 1));
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                MonoInst *ins;
@@ -103,7 +107,7 @@ restart:
 
                        /* FIXME: Optimize this */
                        if (ins->opcode == OP_LDADDR) {
-                               MonoInst *var = ins->inst_p0;
+                               MonoInst *var = (MonoInst *)ins->inst_p0;
 
                                defs [var->dreg] = NULL;
                                /*
@@ -121,7 +125,7 @@ restart:
 
                                        if ((def->opcode == OP_MOVE) && (!defs [def->sreg1] || (def_index [def->sreg1] < def_index [sreg])) && !vreg_is_volatile (cfg, def->sreg1)) {
                                                int vreg = def->sreg1;
-                                               //printf ("CCOPY: R%d -> R%d\n", sreg, vreg);
+                                               if (cfg->verbose_level > 2) printf ("CCOPY: R%d -> R%d\n", sreg, vreg);
                                                ins->dreg = vreg;
                                        }
                                }
@@ -164,12 +168,12 @@ restart:
                                        !vreg_is_volatile (cfg, def->sreg1) &&
                                        /* This avoids propagating local vregs across calls */
                                        ((get_vreg_to_inst (cfg, def->sreg1) || !defs [def->sreg1] || (def_index [def->sreg1] >= last_call_index) || (def->opcode == OP_VMOVE))) &&
-                                       !(defs [def->sreg1] && defs [def->sreg1]->next == def) &&
+                                       !(defs [def->sreg1] && mono_inst_next (defs [def->sreg1], filter) == def) &&
                                        (!MONO_ARCH_USE_FPSTACK || (def->opcode != OP_FMOVE)) &&
                                        (def->opcode != OP_FMOVE)) {
                                        int vreg = def->sreg1;
 
-                                       //printf ("CCOPY: R%d -> R%d\n", sreg, vreg);
+                                       if (cfg->verbose_level > 2) printf ("CCOPY/2: R%d -> R%d\n", sreg, vreg);
                                        sregs [srcindex] = vreg;
                                        mono_inst_set_src_registers (ins, sregs);
 
@@ -226,7 +230,7 @@ restart:
                                        }
                                        else {
                                                /* Special cases */
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
                                                if ((ins->opcode == OP_X86_LEA) && (srcindex == 1)) {
 #if SIZEOF_REGISTER == 8
                                                        /* FIXME: Use OP_PADD_IMM when the new JIT is done */
@@ -252,14 +256,14 @@ restart:
                                         * We have to guarantee that def->sreg1 haven't changed since def->dreg
                                         * was defined. cfg->frame_reg is assumed to remain constant.
                                         */
-                                       if ((def->sreg1 == cfg->frame_reg) || ((def->next == ins) && (def->dreg != def->sreg1))) {
+                                       if ((def->sreg1 == cfg->frame_reg) || ((mono_inst_next (def, filter) == ins) && (def->dreg != def->sreg1))) {
                                                ins->inst_basereg = def->sreg1;
                                                ins->inst_offset += def->inst_imm;
                                        }
-                               } else if ((ins->opcode == OP_ISUB_IMM) && (def->opcode == OP_IADD_IMM) && (def->next == ins)) {
+                               } else if ((ins->opcode == OP_ISUB_IMM) && (def->opcode == OP_IADD_IMM) && (mono_inst_next (def, filter) == ins) && (def->dreg != def->sreg1)) {
                                        ins->sreg1 = def->sreg1;
                                        ins->inst_imm -= def->inst_imm;
-                               } else if ((ins->opcode == OP_IADD_IMM) && (def->opcode == OP_ISUB_IMM) && (def->next == ins)) {
+                               } else if ((ins->opcode == OP_IADD_IMM) && (def->opcode == OP_ISUB_IMM) && (mono_inst_next (def, filter) == ins) && (def->dreg != def->sreg1)) {
                                        ins->sreg1 = def->sreg1;
                                        ins->inst_imm -= def->inst_imm;
                                } else if (ins->opcode == OP_STOREI1_MEMBASE_REG &&
@@ -361,7 +365,7 @@ restart:
 
                                        // We allocated a new vreg, so need to restart
                                        goto restart;
-                               } else if (power2 > 0) {
+                               } else if (power2 > 0 && power2 < 31) {
                                        int r1 = mono_alloc_ireg (cfg);
 
                                        NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_IMM, r1, ins->sreg1, 31);
@@ -428,6 +432,30 @@ reg_is_softreg (int reg, const char spec)
                || (spec == 'v');
 }
 
+static inline gboolean
+mono_is_simd_accessor (MonoInst *ins)
+{
+       switch (ins->opcode) {
+#ifdef MONO_ARCH_SIMD_INTRINSICS
+       case OP_INSERT_I1:
+       case OP_INSERT_I2:
+       case OP_INSERT_I4:
+       case OP_INSERT_I8:
+       case OP_INSERT_R4:
+       case OP_INSERT_R8:
+
+       case OP_INSERTX_U1_SLOW:
+       case OP_INSERTX_I4_SLOW:
+       case OP_INSERTX_R4_SLOW:
+       case OP_INSERTX_R8_SLOW:
+       case OP_INSERTX_I8_SLOW:
+               return TRUE;
+#endif
+       default:
+               return FALSE;
+       }
+}
+
 /**
  * mono_local_deadce:
  *
@@ -484,6 +512,7 @@ mono_local_deadce (MonoCompile *cfg)
                        const char *spec = INS_INFO (ins->opcode);
                        int sregs [MONO_MAX_SRC_REGS];
                        int num_sregs, i;
+                       MonoInst *prev_f = mono_inst_prev (ins, FILTER_NOP | FILTER_IL_SEQ_POINT);
 
                        if (ins->opcode == OP_NOP) {
                                MONO_DELETE_INS (bb, ins);
@@ -492,13 +521,11 @@ mono_local_deadce (MonoCompile *cfg)
 
                        g_assert (ins->opcode > MONO_CEE_LAST);
 
-                       if (MONO_IS_NON_FP_MOVE (ins) && ins->prev) {
+                       if (MONO_IS_NON_FP_MOVE (ins) && prev_f) {
                                MonoInst *def;
                                const char *spec2;
 
-                               def = ins->prev;
-                               while (def->prev && (def->opcode == OP_NOP))
-                                       def = def->prev;
+                               def = prev_f;
                                spec2 = INS_INFO (def->opcode);
 
                                /* 
@@ -507,7 +534,7 @@ mono_local_deadce (MonoCompile *cfg)
                                 * This isn't copyprop, not deadce, but it can only be performed
                                 * after handle_global_vregs () has run.
                                 */
-                               if (!get_vreg_to_inst (cfg, ins->sreg1) && (spec2 [MONO_INST_DEST] != ' ') && (def->dreg == ins->sreg1) && !mono_bitset_test_fast (used, ins->sreg1) && !MONO_IS_STORE_MEMBASE (def) && reg_is_softreg (ins->sreg1, spec [MONO_INST_DEST])) {
+                               if (!get_vreg_to_inst (cfg, ins->sreg1) && (spec2 [MONO_INST_DEST] != ' ') && (def->dreg == ins->sreg1) && !mono_bitset_test_fast (used, ins->sreg1) && !MONO_IS_STORE_MEMBASE (def) && reg_is_softreg (ins->sreg1, spec [MONO_INST_DEST]) && !mono_is_simd_accessor (def)) {
                                        if (cfg->verbose_level > 2) {
                                                printf ("\tReverse copyprop in BB%d on ", bb->block_num);
                                                mono_print_ins (ins);
@@ -529,8 +556,8 @@ mono_local_deadce (MonoCompile *cfg)
                                        (!get_vreg_to_inst (cfg, ins->dreg) || (!bb->extended && !vreg_is_volatile (cfg, ins->dreg) && mono_bitset_test_fast (defined, ins->dreg))) &&
                                        MONO_INS_HAS_NO_SIDE_EFFECT (ins)) {
                                        /* Happens with CMOV instructions */
-                                       if (ins->prev && ins->prev->opcode == OP_ICOMPARE_IMM) {
-                                               MonoInst *prev = ins->prev;
+                                       if (prev_f && prev_f->opcode == OP_ICOMPARE_IMM) {
+                                               MonoInst *prev = prev_f;
                                                /* 
                                                 * Can't use DELETE_INS since that would interfere with the
                                                 * FOR_EACH_INS loop.
@@ -585,3 +612,5 @@ mono_local_deadce (MonoCompile *cfg)
 
        //mono_print_code (cfg, "AFTER LOCAL-DEADCE");
 }
+
+#endif /* DISABLE_JIT */