2007-08-30 Jonathan Chambers <joncham@gmail.com>
[mono.git] / mono / mini / ssa.c
index 8dff2a40c555410359a72c14defe5fba3d27714f..46cbc934ff6308f7c095d704ffd8621e42732bb6 100644 (file)
@@ -11,8 +11,6 @@
 
 #include "mini.h"
 
-extern guint8 mono_burg_arity [];
-
 #define USE_ORIGINAL_VARS
 #define CREATE_PRUNED_SSA
 
@@ -32,6 +30,16 @@ extern guint8 mono_burg_arity [];
        } while (0)
 
 
+static GList*
+g_list_prepend_mempool (GList* l, MonoMemPool* mp, gpointer datum)
+{
+       GList* n = mono_mempool_alloc (mp, sizeof (GList));
+       n->next = l;
+       n->prev = NULL;
+       n->data = datum;
+       return n;
+}
+
 static void 
 unlink_target (MonoBasicBlock *bb, MonoBasicBlock *target)
 {
@@ -94,7 +102,7 @@ replace_usage (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, MonoInst **
 
        arity = mono_burg_arity [inst->opcode];
 
-       if ((inst->ssa_op == MONO_SSA_LOAD || inst->ssa_op == MONO_SSA_MAYBE_LOAD) && 
+       if ((inst->ssa_op == MONO_SSA_LOAD || inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) && 
            (inst->inst_i0->opcode == OP_LOCAL || inst->inst_i0->opcode == OP_ARG)) {
                MonoInst *new_var;
                int idx = inst->inst_i0->inst_c0;
@@ -104,7 +112,7 @@ replace_usage (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, MonoInst **
                } else {
                        new_var = cfg->varinfo [idx];
 
-                       if (new_var->opcode != OP_ARG) {
+                       if ((new_var->opcode != OP_ARG) && (new_var->opcode != OP_LOCAL)) {
                                /* uninitialized variable ? */
                                g_warning ("using uninitialized variables %d in BB%d (%s)", idx, bb->block_num,
                                           mono_method_full_name (cfg->method, TRUE));
@@ -126,13 +134,69 @@ replace_usage (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, MonoInst **
        }
 }
 
+static int
+extends_live (MonoInst *inst)
+{
+       int arity;
+
+       if (!inst)
+               return 0;
+
+       arity = mono_burg_arity [inst->opcode];
+
+       if (inst->ssa_op == MONO_SSA_LOAD && 
+           (inst->inst_i0->opcode == OP_LOCAL || inst->inst_i0->opcode == OP_ARG)) {
+               return 1;
+       } else {
+               if (arity) {
+                       if (inst->ssa_op != MONO_SSA_STORE)
+                               if (extends_live (inst->inst_left))
+                                       return 1;
+                       if (arity > 1)
+                               if (extends_live (inst->inst_right))
+                                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int
+replace_usage_new (MonoCompile *cfg, MonoInst *inst, int varnum, MonoInst *rep)
+{
+       int arity;
+
+       if (!inst)
+               return 0;
+
+       arity = mono_burg_arity [inst->opcode];
+
+       if ((inst->ssa_op == MONO_SSA_LOAD) && 
+           (inst->inst_i0->opcode == OP_LOCAL || inst->inst_i0->opcode == OP_ARG) &&
+           inst->inst_i0->inst_c0 == varnum && rep->type == inst->type) {
+               *inst = *rep;
+               return 1;
+       } else {
+               if (arity) {
+                       if (inst->ssa_op != MONO_SSA_STORE)
+                               if (replace_usage_new (cfg, inst->inst_left, varnum, rep))
+                                       return 1;
+                       if (arity > 1)
+                               if (replace_usage_new (cfg, inst->inst_right, varnum, rep))
+                                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 static void
 mono_ssa_rename_vars (MonoCompile *cfg, int max_vars, MonoBasicBlock *bb, MonoInst **stack) 
 {
        MonoInst *inst, *new_var;
        int i, j, idx;
-       GList *tmp;
-       MonoInst *new_stack [max_vars];
+       GSList *tmp;
+       MonoInst **new_stack;
 
 #ifdef DEBUG_SSA
        printf ("RENAME VARS BB%d %s\n", bb->block_num, mono_method_full_name (cfg->method, TRUE));
@@ -147,7 +211,7 @@ mono_ssa_rename_vars (MonoCompile *cfg, int max_vars, MonoBasicBlock *bb, MonoIn
                        idx = inst->inst_i0->inst_c0;
                        g_assert (idx < max_vars);
 
-                       if (!stack [idx] && bb == cfg->bb_init) {
+                       if ((!stack [idx]) && (bb == cfg->bb_init) && (inst->inst_i0->opcode != OP_ARG)) {
                                new_var = cfg->varinfo [idx];
                        } else {
                                new_var = mono_compile_create_var (cfg, inst->inst_i0->inst_vtype,  inst->inst_i0->opcode);
@@ -189,9 +253,13 @@ mono_ssa_rename_vars (MonoCompile *cfg, int max_vars, MonoBasicBlock *bb, MonoIn
                }
        }
 
-       for (tmp = bb->dominated; tmp; tmp = tmp->next) {
-               memcpy (new_stack, stack, sizeof (MonoInst *) * max_vars); 
-               mono_ssa_rename_vars (cfg, max_vars, (MonoBasicBlock *)tmp->data, new_stack);
+       if (bb->dominated) {
+               new_stack = g_new (MonoInst*, max_vars);
+               for (tmp = bb->dominated; tmp; tmp = tmp->next) {
+                       memcpy (new_stack, stack, sizeof (MonoInst *) * max_vars); 
+                       mono_ssa_rename_vars (cfg, max_vars, (MonoBasicBlock *)tmp->data, new_stack);
+               }
+               g_free (new_stack);
        }
 }
 
@@ -206,7 +274,7 @@ mono_ssa_compute (MonoCompile *cfg)
        g_assert (!(cfg->comp_done & MONO_COMP_SSA));
 
        /* we dont support methods containing exception clauses */
-       g_assert (((MonoMethodNormal *)cfg->method)->header->num_clauses == 0);
+       g_assert (mono_method_get_header (cfg->method)->num_clauses == 0);
        g_assert (!cfg->disable_ssa);
 
        //printf ("COMPUTS SSA %s %d\n", mono_method_full_name (cfg->method, TRUE), cfg->num_varinfo);
@@ -268,6 +336,8 @@ mono_ssa_compute (MonoCompile *cfg)
             
                        store->next = bb->code;
                        bb->code = store;
+                       if (!bb->last_ins)
+                               bb->last_ins = bb->code;
 
 #ifdef DEBUG_SSA
                        printf ("ADD PHI BB%d %s\n", cfg->bblocks [idx]->block_num, mono_method_full_name (cfg->method, TRUE));
@@ -346,7 +416,7 @@ mono_ssa_replace_copies (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, c
 
        arity = mono_burg_arity [inst->opcode];
 
-       if ((inst->ssa_op == MONO_SSA_LOAD || inst->ssa_op == MONO_SSA_MAYBE_LOAD || inst->ssa_op == MONO_SSA_STORE) && 
+       if ((inst->ssa_op == MONO_SSA_LOAD || inst->ssa_op == MONO_SSA_ADDRESS_TAKEN || inst->ssa_op == MONO_SSA_STORE) && 
            (inst->inst_i0->opcode == OP_LOCAL || inst->inst_i0->opcode == OP_ARG)) {
                MonoInst *new_var;
                int idx = inst->inst_i0->inst_c0;
@@ -378,7 +448,7 @@ mono_ssa_replace_copies (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, c
        if (inst->ssa_op == MONO_SSA_STORE && inst->inst_i1->ssa_op == MONO_SSA_LOAD &&
            inst->inst_i0->inst_c0 == inst->inst_i1->inst_i0->inst_c0) {
                inst->ssa_op = MONO_SSA_NOP;
-               inst->opcode = CEE_NOP;
+               inst->opcode = OP_NOP;
        }
 
 }
@@ -423,7 +493,7 @@ mono_ssa_remove (MonoCompile *cfg)
                                }
 
                                /* remove the phi functions */
-                               inst->opcode = CEE_NOP;
+                               inst->opcode = OP_NOP;
                                inst->ssa_op = MONO_SSA_NOP;
                        } 
                }
@@ -437,7 +507,7 @@ mono_ssa_remove (MonoCompile *cfg)
        varlist_array = mono_ssa_get_allocatable_vars (cfg);
 
        for (i = 0; i < varlist_array->len; i++) {
-               GList *l, *t, *regs, *vars = g_ptr_array_index (varlist_array, i);
+               GList *l, *regs, *vars = g_ptr_array_index (varlist_array, i);
                MonoMethodVar *vmv, *amv;
                
                if (g_list_length (vars) <= 1) {
@@ -457,15 +527,15 @@ mono_ssa_remove (MonoCompile *cfg)
                                if (amv->range.last_use.abs_pos >= vmv->range.first_use.abs_pos)
                                        break;
 
-                               active = g_list_remove_link (active, active);
+                               active = g_list_delete_link (active, active);
                                regs = g_list_prepend (regs, (gpointer)amv->reg);
                        }
 
                        if (!regs)
-                               regs = g_list_prepend (regs, vmv->idx);
+                               regs = g_list_prepend (regs, (gpointer)vmv->idx);
 
                        vmv->reg = (int)regs->data;
-                       regs = g_list_remove_link (regs, regs);
+                       regs = g_list_delete_link (regs, regs);
                        active = mono_varlist_insert_sorted (cfg, active, vmv, TRUE);           
                }
 
@@ -509,16 +579,37 @@ typedef struct {
        MonoInst *inst;
 } MonoVarUsageInfo;
 
-static void
+
+
+
+/*
+ * Returns TRUE if the tree can have side effects.
+ */
+static gboolean
 analyze_dev_use (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *root, MonoInst *inst)
 {
        MonoMethodVar *info;
        int i, idx, arity;
+       gboolean has_side_effects;
 
        if (!inst)
-               return;
+               return FALSE;
 
        arity = mono_burg_arity [inst->opcode];
+       switch (inst->opcode) {
+#define ANALYZE_DEV_USE_SPECIFIC_OPS 1
+#define OPDEF(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) case a1:
+#include "simple-cee-ops.h"
+#undef OPDEF
+#define MINI_OP(a1,a2) case a1:
+#include "simple-mini-ops.h"
+#undef MINI_OP
+#undef ANALYZE_DEV_USE_SPECIFIC_OPS
+               has_side_effects = FALSE;
+               break;
+       default:
+               has_side_effects = TRUE;
+       }
 
        if ((inst->ssa_op == MONO_SSA_STORE) && 
            (inst->inst_i0->opcode == OP_LOCAL /*|| inst->inst_i0->opcode == OP_ARG */)) {
@@ -544,12 +635,12 @@ analyze_dev_use (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *root, MonoInst
                                //printf ("FOUND %d\n", idx);
                                ui->bb = bb;
                                ui->inst = root;
-                               info->uses = g_list_prepend (info->uses, ui);
+                               info->uses = g_list_prepend_mempool (info->uses, cfg->mempool, ui);
                        }
                }
        }
 
-       if ((inst->ssa_op == MONO_SSA_LOAD || inst->ssa_op == MONO_SSA_MAYBE_LOAD) && 
+       if ((inst->ssa_op == MONO_SSA_LOAD || inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) && 
            (inst->inst_i0->opcode == OP_LOCAL || inst->inst_i0->opcode == OP_ARG)) {
                MonoVarUsageInfo *ui = mono_mempool_alloc (cfg->mempool, sizeof (MonoVarUsageInfo));
                idx = inst->inst_i0->inst_c0;   
@@ -557,17 +648,22 @@ analyze_dev_use (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *root, MonoInst
                //printf ("FOUND %d\n", idx);
                ui->bb = bb;
                ui->inst = root;
-               info->uses = g_list_prepend (info->uses, ui);
+               info->uses = g_list_prepend_mempool (info->uses, cfg->mempool, ui);
        } else {
                if (arity) {
                        //if (inst->ssa_op != MONO_SSA_STORE)
-                       analyze_dev_use (cfg, bb, root, inst->inst_left);
+                       if (analyze_dev_use (cfg, bb, root, inst->inst_left))
+                               has_side_effects = TRUE;
                        if (arity > 1)
-                               analyze_dev_use (cfg, bb, root, inst->inst_right);
+                               if (analyze_dev_use (cfg, bb, root, inst->inst_right))
+                                       has_side_effects = TRUE;
                }
        }
+       
+       return has_side_effects;
 }
 
+
 /* avoid unnecessary copies of variables:
  * Y <= X; Z = Y; is translated to Z = X;
  */
@@ -582,9 +678,29 @@ mono_ssa_avoid_copies (MonoCompile *cfg)
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                for (inst = bb->code; inst; inst = inst->next) {
-                       if (inst->ssa_op == MONO_SSA_STORE && inst->inst_i0->opcode == OP_LOCAL) {
+                       if (inst->ssa_op == MONO_SSA_STORE && inst->inst_i0->opcode == OP_LOCAL &&
+                           !IS_CALL (inst->inst_i1->opcode) && inst->inst_i1->opcode != OP_PHI && !inst->flags) {
                                i1 = cfg->vars [inst->inst_i0->inst_c0];
 
+/* fixme: compiling mcs does not work when I enable this */
+#if 0
+                               if (g_list_length (i1->uses) == 1 && !extends_live (inst->inst_i1)) {
+                                       MonoVarUsageInfo *vi = (MonoVarUsageInfo *)i1->uses->data;
+                                       u = vi->inst;
+
+                                       //printf ("VAR %d %s\n", i1->idx, mono_method_full_name (cfg->method, TRUE));
+                                       //mono_print_tree (inst); printf ("\n");
+                                       //mono_print_tree (u); printf ("\n");
+
+                                       if (replace_usage_new (cfg, u, inst->inst_i0->inst_c0,  inst->inst_i1)) {
+                                                                                                               
+                                               //mono_print_tree (u); printf ("\n");
+                                                       
+                                               inst->opcode = OP_NOP;
+                                               inst->ssa_op = MONO_SSA_NOP;
+                                       }
+                               }
+#endif                 
                                if ((next = inst->next) && next->ssa_op == MONO_SSA_STORE && next->inst_i0->opcode == OP_LOCAL &&
                                    next->inst_i1->ssa_op == MONO_SSA_LOAD &&  next->inst_i1->inst_i0->opcode == OP_LOCAL &&
                                    next->inst_i1->inst_i0->inst_c0 == inst->inst_i0->inst_c0 && g_list_length (i1->uses) == 1 &&
@@ -594,9 +710,8 @@ mono_ssa_avoid_copies (MonoCompile *cfg)
                                        inst->inst_i0 = next->inst_i0;
                                        i2->def = inst;
                                        i1->def = NULL;
-                                       g_list_free (i1->uses);
                                        i1->uses = NULL;
-                                       next->opcode = CEE_NOP;
+                                       next->opcode = OP_NOP;
                                        next->ssa_op = MONO_SSA_NOP;
                                }
                        }
@@ -614,7 +729,11 @@ mono_ssa_create_def_use (MonoCompile *cfg)
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                MonoInst *inst;
                for (inst = bb->code; inst; inst = inst->next) {
-                       analyze_dev_use (cfg, bb, inst, inst);
+                       gboolean has_side_effects = analyze_dev_use (cfg, bb, inst, inst);
+                       if (has_side_effects && (inst->ssa_op == MONO_SSA_STORE) && 
+                                       (inst->inst_i0->opcode == OP_LOCAL || inst->inst_i0->opcode == OP_ARG)) {
+                               inst->inst_i0->flags |= MONO_INST_DEFINITION_HAS_SIDE_EFFECTS;
+                       }
                }
        }
 
@@ -652,9 +771,40 @@ simulate_compare (int opcode, int a, int b)
        return 0;
 }
 
+static int
+simulate_long_compare (int opcode, gint64 a, gint64 b)
+{
+       switch (opcode) {
+       case CEE_BEQ:
+               return a == b;
+       case CEE_BGE:
+               return a >= b;
+       case CEE_BGT:
+               return a > b;
+       case CEE_BLE:
+               return a <= b;
+       case CEE_BLT:
+               return a < b;
+       case CEE_BNE_UN:
+               return a != b;
+       case CEE_BGE_UN:
+               return (guint64)a >= (guint64)b;
+       case CEE_BGT_UN:
+               return (guint64)a > (guint64)b;
+       case CEE_BLE_UN:
+               return (guint64)a <= (guint64)b;
+       case CEE_BLT_UN:
+               return (guint64)a < (guint64)b;
+       default:
+               g_assert_not_reached ();
+       }
+
+       return 0;
+}
+
 #define EVAL_CXX(name,op,cast) \
        case name:      \
-               if (inst->inst_i0->opcode == OP_COMPARE) { \
+               if ((inst->inst_i0->opcode == OP_COMPARE) || (inst->inst_i0->opcode == OP_LCOMPARE)) { \
                        r1 = evaluate_const_tree (cfg, inst->inst_i0->inst_i0, &a, carray); \
                        r2 = evaluate_const_tree (cfg, inst->inst_i0->inst_i1, &b, carray); \
                        if (r1 == 1 && r2 == 1) { \
@@ -679,6 +829,7 @@ simulate_compare (int opcode, int a, int b)
                break;
 
 
+/* fixme: this only works for interger constants, but not for other types (long, float) */
 static int
 evaluate_const_tree (MonoCompile *cfg, MonoInst *inst, int *res, MonoInst **carray)
 {
@@ -754,14 +905,22 @@ fold_tree (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, MonoInst **carr
        }
 
        if ((inst->opcode >= CEE_BEQ && inst->opcode <= CEE_BLT_UN) &&
-           inst->inst_i0->opcode == OP_COMPARE) {
+           ((inst->inst_i0->opcode == OP_COMPARE) || (inst->inst_i0->opcode == OP_LCOMPARE))) {
                MonoInst *v0 = inst->inst_i0->inst_i0;
                MonoInst *v1 = inst->inst_i0->inst_i1;
+               MonoBasicBlock *target = NULL;
 
-               if (evaluate_const_tree (cfg, v0, &a, carray) == 1 &&
-                   evaluate_const_tree (cfg, v1, &b, carray) == 1) {
-                       MonoBasicBlock *target;
-                               
+               /* hack for longs to optimize the simply cases */
+               if (v0->opcode == OP_I8CONST && v1->opcode == OP_I8CONST) {
+                       if (simulate_long_compare (inst->opcode, v0->inst_l, v1->inst_l)) {
+                               //unlink_target (bb, inst->inst_false_bb);
+                               target = inst->inst_true_bb;
+                       } else {
+                               //unlink_target (bb, inst->inst_true_bb);
+                               target = inst->inst_false_bb;
+                       }                       
+               } else if (evaluate_const_tree (cfg, v0, &a, carray) == 1 &&
+                          evaluate_const_tree (cfg, v1, &b, carray) == 1) {                            
                        if (simulate_compare (inst->opcode, a, b)) {
                                //unlink_target (bb, inst->inst_false_bb);
                                target = inst->inst_true_bb;
@@ -769,17 +928,19 @@ fold_tree (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, MonoInst **carr
                                //unlink_target (bb, inst->inst_true_bb);
                                target = inst->inst_false_bb;
                        }
-                       
+               }
+
+               if (target) {
                        bb->out_bb [0] = target;
                        bb->out_count = 1;
-                       inst->opcode = CEE_BR;
+                       inst->opcode = OP_BR;
                        inst->inst_target_bb = target;
                }
-       } else if (inst->opcode == CEE_SWITCH && evaluate_const_tree (cfg, inst->inst_left, &a, carray) == 1) {
+       } else if (inst->opcode == CEE_SWITCH && (evaluate_const_tree (cfg, inst->inst_left, &a, carray) == 1) && (a >= 0) && (a < GPOINTER_TO_INT (inst->klass))) {
                bb->out_bb [0] = inst->inst_many_bb [a];
                bb->out_count = 1;
                inst->inst_target_bb = bb->out_bb [0];
-               inst->opcode = CEE_BR;
+               inst->opcode = OP_BR;
        }
 
 }
@@ -811,8 +972,11 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, GList **cvars,
 
        if (inst->opcode == CEE_SWITCH) {
                int r1, i, a;
+               int cases = GPOINTER_TO_INT (inst->klass);
 
                r1 = evaluate_const_tree (cfg, inst->inst_left, &a, carray);
+               if ((r1 == 1) && ((a < 0) || (a >= cases)))
+                       r1 = 2;
                if (r1 == 1) {
                        MonoBasicBlock *tb = inst->inst_many_bb [a];
                        if (!(tb->flags &  BB_REACHABLE)) {
@@ -820,7 +984,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, GList **cvars,
                                *bblist = g_list_prepend (*bblist, tb);
                        }
                } else if (r1 == 2) {
-                       for (i = (int)inst->klass; i >= 0; i--) {
+                       for (i = GPOINTER_TO_INT (inst->klass); i >= 0; i--) {
                                MonoBasicBlock *tb = inst->inst_many_bb [i];
                                if (!(tb->flags &  BB_REACHABLE)) {
                                        tb->flags |= BB_REACHABLE;
@@ -828,8 +992,15 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, GList **cvars,
                                }
                        }
                }
+       } else if (inst->opcode == OP_BR) {
+               MonoBasicBlock *target = inst->inst_target_bb;
+
+               if (!(target->flags &  BB_REACHABLE)) {
+                       target->flags |= BB_REACHABLE;
+                       *bblist = g_list_prepend (*bblist, target);
+               }
        } else if ((inst->opcode >= CEE_BEQ && inst->opcode <= CEE_BLT_UN) &&
-           inst->inst_i0->opcode == OP_COMPARE) {
+           ((inst->inst_i0->opcode == OP_COMPARE) || (inst->inst_i0->opcode == OP_LCOMPARE))) {
                int a, b, r1, r2;
                MonoInst *v0 = inst->inst_i0->inst_i0;
                MonoInst *v1 = inst->inst_i0->inst_i1;
@@ -922,13 +1093,15 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, GList **cvars,
 void
 mono_ssa_cprop (MonoCompile *cfg) 
 {
-       MonoInst *carray [cfg->num_varinfo];
+       MonoInst **carray;
        MonoBasicBlock *bb;
        GList *bblock_list, *cvars;
        GList *tmp;
        int i;
        //printf ("SIMPLE OPTS BB%d %s\n", bb->block_num, mono_method_full_name (cfg->method, TRUE));
 
+       carray = g_new0 (MonoInst*, cfg->num_varinfo);
+
        if (!(cfg->comp_done & MONO_COMP_SSA_DEF_USE))
                mono_ssa_create_def_use (cfg);
 
@@ -950,7 +1123,7 @@ mono_ssa_cprop (MonoCompile *cfg)
 
                bb = (MonoBasicBlock *)bblock_list->data;
 
-               bblock_list = g_list_remove_link (bblock_list, bblock_list);
+               bblock_list = g_list_delete_link (bblock_list, bblock_list);
 
                g_assert (bb->flags &  BB_REACHABLE);
 
@@ -967,7 +1140,7 @@ mono_ssa_cprop (MonoCompile *cfg)
 
                while (cvars) {
                        MonoMethodVar *info = (MonoMethodVar *)cvars->data;                     
-                       cvars = g_list_remove_link (cvars, cvars);
+                       cvars = g_list_delete_link (cvars, cvars);
 
                        for (tmp = info->uses; tmp; tmp = tmp->next) {
                                MonoVarUsageInfo *ui = (MonoVarUsageInfo *)tmp->data;
@@ -985,6 +1158,8 @@ mono_ssa_cprop (MonoCompile *cfg)
                }
        }
 
+       g_free (carray);
+
        cfg->comp_done |= MONO_COMP_REACHABILITY;
 }
 
@@ -998,6 +1173,7 @@ add_to_dce_worklist (MonoCompile *cfg, MonoMethodVar *var, MonoMethodVar *use, G
        for (tmp = use->uses; tmp; tmp = tmp->next) {
                MonoVarUsageInfo *ui = (MonoVarUsageInfo *)tmp->data;
                if (ui->inst == var->def) {
+                       /* from the mempool */
                        use->uses = g_list_remove_link (use->uses, tmp);
                        break;
                }
@@ -1031,13 +1207,15 @@ mono_ssa_deadce (MonoCompile *cfg)
        for (i = 0; i < cfg->num_varinfo; i++) {
                MonoMethodVar *info = cfg->vars [i];
                work_list = g_list_prepend (work_list, info);
+               
+               //if ((info->def != NULL) && (info->def->inst_i1->opcode != OP_PHI)) printf ("SSA DEADCE TOTAL LOCAL\n");
        }
 
        while (work_list) {
                MonoMethodVar *info = (MonoMethodVar *)work_list->data;
-               work_list = g_list_remove_link (work_list, work_list);
+               work_list = g_list_delete_link (work_list, work_list);
 
-               if (!info->uses && info->def) {
+               if (!info->uses && info->def && (!(cfg->varinfo [info->idx]->flags & (MONO_INST_DEFINITION_HAS_SIDE_EFFECTS|MONO_INST_VOLATILE|MONO_INST_INDIRECT)))) {
                        MonoInst *i1;
                        //printf ("ELIMINATE %s: ", mono_method_full_name (cfg->method, TRUE)); mono_print_tree (info->def); printf ("\n");
 
@@ -1053,8 +1231,9 @@ mono_ssa_deadce (MonoCompile *cfg)
                                        MonoMethodVar *u = cfg->vars [i1->inst_i0->inst_c0];
                                        add_to_dce_worklist (cfg, info, u, &work_list);
                        }
+                       //if (i1->opcode != OP_PHI) printf ("SSA DEADCE DEAD LOCAL\n");
 
-                       info->def->opcode = CEE_NOP;
+                       info->def->opcode = OP_NOP;
                        info->def->ssa_op = MONO_SSA_NOP;
                }