added linear scan to mono (use --ls to enable it)
authorDietmar Maurer <dietmar@mono-cvs.ximian.com>
Thu, 9 May 2002 11:16:20 +0000 (11:16 -0000)
committerDietmar Maurer <dietmar@mono-cvs.ximian.com>
Thu, 9 May 2002 11:16:20 +0000 (11:16 -0000)
svn path=/trunk/mono/; revision=4440

12 files changed:
mono/benchmark/Makefile.am
mono/benchmark/loops.cs [new file with mode: 0755]
mono/jit/ChangeLog
mono/jit/Makefile.am
mono/jit/emit-x86.c
mono/jit/exception.c
mono/jit/jit.c
mono/jit/jit.h
mono/jit/linear-scan.c [new file with mode: 0644]
mono/jit/mono.c
mono/jit/trampoline.c
mono/jit/x86.brg

index 46b086f77bc7aa8e1bb40518e7341c6fde81f6f8..eec81796cd5af57c644c47359faf3bd6c99f4bde 100644 (file)
@@ -11,7 +11,8 @@ TESTSRC=                      \
        inline1.cs              \
        inline2.cs              \
        inline3.cs              \
-       muldiv.cs
+       muldiv.cs               \
+       loops.cs
 
 TESTSI=$(TESTSRC:.cs=.exe)
 TESTBS=$(BENCHSRC:.cs=.exe)
diff --git a/mono/benchmark/loops.cs b/mono/benchmark/loops.cs
new file mode 100755 (executable)
index 0000000..da009e1
--- /dev/null
@@ -0,0 +1,45 @@
+using System;
+
+public class NestedLoop {
+       static public int nest_test () {
+               int n = 16;
+               int x = 0;
+               int a = n;
+               while (a-- != 0) {
+                   int b = n;
+                   while (b-- != 0) {
+                       int c = n;
+                       while (c-- != 0) {
+                           int d = n;
+                       while (d-- != 0) {
+                               int e = n;
+                               while (e-- != 0) {
+                                   int f = n;
+                                   while (f-- != 0) {
+                                       x++;
+                                   }
+                               }
+                       }
+                       }
+                   }
+               }
+               return x;
+       }
+
+       public static int Main (string[] args) {
+               int repeat = 1;
+               
+               if (args.Length == 1)
+                       repeat = Convert.ToInt32 (args [0]);
+               
+               Console.WriteLine ("Repeat = " + repeat);
+
+               for (int i = 0; i < repeat*10; i++)
+                       if (nest_test () != 16777216)
+                               return 1;
+               
+               return 0;
+       }
+}
+
+
index 12a023edb89346e28984cbfb174567aa986230df..93503d5a0c02343be1d51cb7877669c1a14a5f21 100644 (file)
@@ -1,3 +1,25 @@
+2002-05-09  Dietmar Maurer  <dietmar@ximian.com>
+
+       * linear-scan.c: linear scan reg. allocation and data flow analysis
+
+       * jit.c (arch_allocate_var): add live range info
+       (mono_cfg_add_successor): create list of successors for basic
+       blocks.
+
+       * mono.c (main): new option --ls to enable linear scan
+
+       * exception.c (arch_handle_exception): print instruction pointer
+       relative to method start address.
+
+       * jit.c (mono_print_ctree): print register number if locals are
+       allocate in registers.
+
+       * emit-x86.c (arch_emit_prologue): initialize reg. allocated locals
+       (arch_emit_epilogue): take care when restoring save registers,
+       because the stack pointer may has changed.
+
+       * x86.brg: s/VAROFFSET/VARINFO/
+       modified to support global register allocation
 
 Mon May 6 15:38:15 CEST 2002 Paolo Molaro <lupus@ximian.com>
 
index 10af4e92a8bcaceda1a52380422f31549078fa94..cf444b69c1b5ed262ce26204734d524bde3f4ef7 100644 (file)
@@ -28,7 +28,8 @@ libmono_a_SOURCES =                   \
        delegate.c              \
        exception.c             \
        invoke.c                \
-       message.c
+       message.c               \
+       linear-scan.c
 
 mono_SOURCES = mono.c
 
index a6d1adea705ab143e0082fe538a419ad5d59f699..ddfe6bc78fe0dc57fdc7b764642d83ea6407d4e4 100644 (file)
@@ -326,10 +326,17 @@ arch_emit_prologue (MonoFlowGraph *cfg)
        if (header->num_locals) {
 
                if (header->init_locals) {
-                       int offset = g_array_index (cfg->varinfo, MonoVarInfo, 
-                                                   cfg->locals_start_index + header->num_locals - 1).offset;  
+                       MonoVarInfo *vi = &VARINFO (cfg, cfg->locals_start_index + header->num_locals - 1);
+                       int offset = vi->offset;  
                        int size = - offset;
 
+                       for (i = 0; i < header->num_locals; ++i) {
+                               MonoVarInfo *rv = &VARINFO (cfg, cfg->locals_start_index + header->num_locals - 1);
+
+                               if (rv->reg >= 0)
+                                       x86_alu_reg_imm (cfg->code, X86_XOR, rv->reg, rv->reg);
+                       }
+
                        if (size == 1 || size == 2 || size == 4) {
                                x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, size);
                                return;
@@ -364,7 +371,7 @@ arch_emit_prologue (MonoFlowGraph *cfg)
 
                        for (i = 0; i < header->num_locals; ++i) {
                                MonoType *t = header->locals [i];
-                               int offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->locals_start_index + i).offset;  
+                               int offset = VARINFO (cfg, cfg->locals_start_index + i).offset;  
 
                                if (t->byref) {
                                        x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
@@ -395,6 +402,7 @@ arch_emit_prologue (MonoFlowGraph *cfg)
 static void
 arch_emit_epilogue (MonoFlowGraph *cfg)
 {
+       int pos = 4;
        /*
         * note: with trace and profiling the value on the FP stack may get clobbered.
         */
@@ -423,14 +431,18 @@ arch_emit_epilogue (MonoFlowGraph *cfg)
                x86_pop_reg (cfg->code, X86_EAX);
        }
 
-       if (mono_regset_reg_used (cfg->rs, X86_ESI))
-               x86_pop_reg (cfg->code, X86_ESI);
-
-       if (mono_regset_reg_used (cfg->rs, X86_EDI))
-               x86_pop_reg (cfg->code, X86_EDI);
-
-       if (mono_regset_reg_used (cfg->rs, X86_EBX))
-               x86_pop_reg (cfg->code, X86_EBX);
+       if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+               x86_mov_reg_membase (cfg->code, X86_EBX, X86_EBP, - (cfg->locals_size + pos), 4);
+               pos += 4;
+       }
+       if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+               x86_mov_reg_membase (cfg->code, X86_EDI, X86_EBP, - (cfg->locals_size + pos), 4);
+               pos += 4;
+       }
+       if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+               x86_mov_reg_membase (cfg->code, X86_ESI, X86_EBP, - (cfg->locals_size + pos), 4);
+               pos += 4;
+       }
 
        x86_leave (cfg->code);
        x86_ret (cfg->code);
@@ -461,9 +473,9 @@ mono_label_cfg (MonoFlowGraph *cfg)
                                if (mono_debug_handle)
                                        return;
                                g_warning ("tree does not match");
-                               mono_print_ctree (t1); printf ("\n\n");
+                               mono_print_ctree (cfg, t1); printf ("\n\n");
 
-                               mono_print_forest (forest);
+                               mono_print_forest (cfg, forest);
                                g_assert_not_reached ();
                        }
                }
@@ -471,7 +483,8 @@ mono_label_cfg (MonoFlowGraph *cfg)
 }
 
 static gboolean
-tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs, guint8 exclude_mask, int *spillcount) 
+tree_allocate_regs (MonoFlowGraph *cfg, MBTree *tree, int goal, MonoRegSet *rs, 
+                   guint8 exclude_mask, int *spillcount) 
 {
        MBTree *kids[10];
        int ern = mono_burg_rule (tree->state, goal);
@@ -511,7 +524,7 @@ tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs, guint8 exclude_mask,
 
        if (nts [0] && kids [0] == tree) {
                /* chain rule */
-               if (!tree_allocate_regs (kids [0], nts [0], rs, exclude_mask, spillcount))
+               if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, exclude_mask, spillcount))
                        return FALSE;
                /* special case reg: coni4 */
                if (goal == MB_NTERM_reg) {
@@ -541,15 +554,15 @@ tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs, guint8 exclude_mask,
        if (nts [0]) {
                if (nts [1]) { /* two kids */
                        MonoRegSet saved_rs;
-                       if (nts [2]) /* we cant handle tree kids */
+                       if (nts [2]) /* we cant handle three kids */
                                g_assert_not_reached ();
 
-                       if (!tree_allocate_regs (kids [0], nts [0], rs, left_exclude_mask, spillcount))
+                       if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, left_exclude_mask, spillcount))
                                return FALSE;
 
                        saved_rs = *rs;
 
-                       if (!tree_allocate_regs (kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
+                       if (!tree_allocate_regs (cfg, kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
 
 #ifdef DEBUG_REGALLOC
                                printf ("tree_allocate_regs try 1 failed %d %d %d %d\n", 
@@ -577,7 +590,7 @@ tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs, guint8 exclude_mask,
 
                                kids [0]->spilled = 1;
 
-                               if (!tree_allocate_regs (kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
+                               if (!tree_allocate_regs (cfg, kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
 #ifdef DEBUG_REGALLOC
                                        printf ("tree_allocate_regs try 2 failed\n");
 #endif
@@ -589,7 +602,7 @@ tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs, guint8 exclude_mask,
                        }
 
                } else { /* one kid */
-                       if (!tree_allocate_regs (kids [0], nts [0], rs, left_exclude_mask, spillcount))
+                       if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, left_exclude_mask, spillcount))
                                return FALSE;                   
                }
        }
@@ -716,8 +729,8 @@ arch_allocate_regs (MonoFlowGraph *cfg)
 #ifdef DEBUG_REGALLOC
                        printf ("arch_allocate_regs start %d:%d %08x\n", i, j, cfg->rs->free_mask);
 #endif
-                       if (!tree_allocate_regs (t1, 1, cfg->rs, 0, &spillcount)) {
-                               mono_print_ctree (t1);
+                       if (!tree_allocate_regs (cfg, t1, 1, cfg->rs, 0, &spillcount)) {
+                               mono_print_ctree (cfg, t1);
                                g_error ("register allocation failed");
                        }
 
@@ -739,7 +752,7 @@ arch_allocate_regs (MonoFlowGraph *cfg)
                int spillvar;
                spillvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer),
                                              MONO_TEMPVAR, VAL_I32);
-               cfg->spillvars [i] = VAROFFSET (cfg, spillvar);
+               cfg->spillvars [i] = VARINFO (cfg, spillvar).offset;
        }
 }
 
@@ -770,7 +783,7 @@ tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree, int *spillcount)
                                        cfg->method->klass->name_space,
                                        cfg->method->klass->name, cfg->method->name);
 
-                               mono_print_ctree (kids [0]);printf ("\n\n");
+                               mono_print_ctree (cfg, kids [0]);printf ("\n\n");
 #endif
                                spilloffset1 = 0;
                                spilloffset2 = 0;
@@ -823,7 +836,7 @@ tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree, int *spillcount)
 
        tree->addr = offset = cfg->code - cfg->start;
 
-       // we assume an instruction uses a maximum of 128 bytes
+       /* we assume an instruction uses a maximum of 128 bytes */
        if ((cfg->code_size - offset) <= 128) {
                int add = MIN (cfg->code_size, 128);
                cfg->code_size += add;
@@ -1046,6 +1059,7 @@ arch_compile_method (MonoMethod *method)
                MonoFlowGraph *cfg;
                MonoMemPool *mp;
                gulong code_size_ratio;
+               guint32 ls_used_mask = 0;
        
                mono_profiler_method_jit (method);
        
@@ -1088,17 +1102,23 @@ arch_compile_method (MonoMethod *method)
                if (mono_debug_insert_breakpoint > 0)
                        mono_debug_insert_breakpoint--;
 
+               if (mono_use_linear_scan) {
+                       mono_linear_scan (cfg, &ls_used_mask);
+                       cfg->rs->used_mask |= ls_used_mask;
+               }
+
                if (mono_jit_dump_forest) {
                        int i;
                        printf ("FOREST %s.%s:%s\n", method->klass->name_space,
                                method->klass->name, method->name);
                        for (i = 0; i < cfg->block_count; i++) {
                                printf ("BLOCK %d:\n", i);
-                               mono_print_forest (cfg->bblocks [i].forest);
+                               mono_print_forest (cfg, cfg->bblocks [i].forest);
                        }
                }
-       
+                       
                mono_label_cfg (cfg);
+
                if (cfg->invalid) {
                        mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
                        return NULL;
index 771e07e9e9fb9fc6e195fc28ebd54a0faf76535d..981b0d99bc356e6c99cc2d5cd95eb1e7f6c7b496 100644 (file)
@@ -204,8 +204,8 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj)
                                strace = g_strdup ("");
                        }
 
-                       tmp = g_strdup_printf ("%sin %s.%s:%s ()\n", strace, m->klass->name_space,  
-                                              m->klass->name, m->name);
+                       tmp = g_strdup_printf ("%sin %03x %s.%s:%s ()\n", strace, ip - ji->code_start,
+                                              m->klass->name_space, m->klass->name, m->name);
 
                        g_free (strace);
 
index 65c004e604a3e534f9153282b7c224a3855d4927..c994d377ab635a7a5281c071643a4df7d06f0bdd 100644 (file)
@@ -193,6 +193,9 @@ gboolean mono_jit_profile = FALSE;
 /* Force jit to share code between application domains */
 gboolean mono_jit_share_code = FALSE;
 
+/* use linear scan register allocation */
+gboolean mono_use_linear_scan = FALSE;
+
 /* inline code */
 gboolean mono_jit_inline_code = TRUE;
 
@@ -649,7 +652,7 @@ map_call_type (MonoType *type, MonoValueType *svt)
  * prints the tree to stdout
  */
 void
-mono_print_ctree (MBTree *tree)
+mono_print_ctree (MonoFlowGraph *cfg, MBTree *tree)
 {
        int arity;
 
@@ -665,15 +668,20 @@ mono_print_ctree (MBTree *tree)
 
        switch (tree->op) {
        case MB_TERM_CONST_I4:
-       case MB_TERM_ADDR_L:
                printf ("[%d]", tree->data.i);
                break;
+       case MB_TERM_ADDR_L:
+               if (VARINFO (cfg, tree->data.i).reg >= 0)
+                       printf ("[R%d]", tree->data.i);
+               else
+                       printf ("[%d]", tree->data.i);
+               break;
        }
 
        g_assert (!(tree->right && !tree->left));
 
-       mono_print_ctree (tree->left);
-       mono_print_ctree (tree->right);
+       mono_print_ctree (cfg, tree->left);
+       mono_print_ctree (cfg, tree->right);
 
        if (arity)
                printf (")");
@@ -683,7 +691,7 @@ mono_print_ctree (MBTree *tree)
  * prints the whole forest to stdout
  */
 void
-mono_print_forest (GPtrArray *forest)
+mono_print_forest (MonoFlowGraph *cfg, GPtrArray *forest)
 {
        const int top = forest->len;
        int i;
@@ -691,7 +699,7 @@ mono_print_forest (GPtrArray *forest)
        for (i = 0; i < top; i++) {
                MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
                printf ("       ");
-               mono_print_ctree (t);
+               mono_print_ctree (cfg, t);
                printf ("\n");
        }
 
@@ -730,6 +738,16 @@ arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoValueKind kind,
 
        mono_jit_stats.allocate_var++;
 
+       vi.range.last_use.abs_pos = 0;
+       vi.range.first_use.pos.bid = 0xffff;
+       vi.range.first_use.pos.tid = 0; 
+       vi.isvolatile = 0;
+       vi.reg = -1;
+       vi.varnum = cfg->varinfo->len;
+
+       if (size != sizeof (gpointer))
+               vi.isvolatile = 1;
+       
        switch (kind) {
        case MONO_TEMPVAR:
        case MONO_LOCALVAR: {
@@ -1064,6 +1082,7 @@ mono_cfg_free (MonoFlowGraph *cfg)
                if (!cfg->bblocks [i].reached)
                        continue;
                g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
+               g_list_free (cfg->bblocks [i].succ);
        }
 
        if (cfg->bcinfo)
@@ -1100,6 +1119,27 @@ mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, int type)
        return NULL;
 }
 
+static void
+mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
+{
+       MonoBBlock *tbb;
+       GList *l;
+
+       g_assert (cfg->bcinfo [target].is_block_start);
+
+       tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
+       g_assert (tbb);
+
+       for (l = bb->succ; l; l = l->next) {
+               MonoBBlock *t = (MonoBBlock *)l->data;
+               if (t == tbb)
+                       return;
+       }
+
+       bb->succ = g_list_prepend (bb->succ, tbb);
+}
+
+
 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
 
 void
@@ -1244,6 +1284,7 @@ mono_analyze_flow (MonoFlowGraph *cfg)
        for (i = 0; i < header->code_size; i++) {
                if (bcinfo [i].is_block_start) {
                        bb->cli_addr = i;
+                       bb->num = block_count;
                        if (block_count)
                                bb [-1].length = i - bb [-1].cli_addr; 
                        bcinfo [i].block_id = block_count;
@@ -1256,6 +1297,91 @@ mono_analyze_flow (MonoFlowGraph *cfg)
        cfg->bcinfo = bcinfo;
        cfg->bblocks = bblocks;
        cfg->block_count = block_count;
+       
+       ip = header->code;
+       end = ip + header->code_size;
+       bb = NULL;
+
+       while (ip < end) {
+               guint32 cli_addr = ip - header->code;
+
+               if (bcinfo [cli_addr].is_block_start) {
+                       MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];           
+                       if (bb && !bb->succ)
+                               bb->succ = g_list_prepend (bb->succ, tbb);
+                       bb = tbb;
+               }
+               g_assert (bb);
+
+               if (*ip == 0xfe) {
+                       ++ip;
+                       i = *ip + 256;
+               } else {
+                       i = *ip;
+               }
+
+               opcode = &mono_opcodes [i];
+
+               switch (opcode->argument) {
+               case MonoInlineNone:
+                       ++ip;
+                       break;
+               case MonoInlineString:
+               case MonoInlineType:
+               case MonoInlineField:
+               case MonoInlineMethod:
+               case MonoInlineTok:
+               case MonoInlineSig:
+               case MonoShortInlineR:
+               case MonoInlineI:
+                       ip += 5;
+                       break;
+               case MonoInlineVar:
+                       ip += 3;
+                       break;
+               case MonoShortInlineVar:
+               case MonoShortInlineI:
+                       ip += 2;
+                       break;
+               case MonoShortInlineBrTarget:
+                       ip++;
+                       i = (signed char)*ip;
+                       ip++;
+                       mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
+                       if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
+                               mono_cfg_add_successor (cfg, bb, cli_addr + 2);
+                       break;
+               case MonoInlineBrTarget:
+                       ip++;
+                       i = read32 (ip);
+                       ip += 4;
+                       mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
+                       if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
+                               mono_cfg_add_successor (cfg, bb, cli_addr + 5);
+                       break;
+               case MonoInlineSwitch: {
+                       gint32 st, target, n;
+                       ++ip;
+                       n = read32 (ip);
+                       ip += 4;
+                       st = cli_addr + 5 + 4 * n;
+                       mono_cfg_add_successor (cfg, bb, st);
+
+                       for (i = 0; i < n; i++) {
+                               target = read32 (ip) + st;
+                               ip += 4;
+                               mono_cfg_add_successor (cfg, bb, target);
+                       }
+                       break;
+               }
+               case MonoInlineR:
+               case MonoInlineI8:
+                       ip += 9;
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+       }
 }
 
 /**
@@ -1717,8 +1843,10 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                int size, align;
                
                for (i = 0; i < header->num_locals; ++i) {
+                       MonoValueType svt;
                        size = mono_type_size (header->locals [i], &align);
-                       varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
+                       map_ldind_type (header->locals [i], &svt);
+                       varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
                        if (i == 0)
                                cfg->locals_start_index = varnum;
                }
@@ -1740,15 +1868,19 @@ mono_analyze_stack (MonoFlowGraph *cfg)
        cfg->args_start_index = firstarg = varnum + 1;
  
        if (signature->hasthis) {
-               arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
+               int thisvar;
+               thisvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
+               VARINFO (cfg, thisvar).isvolatile = 1;
        }
 
        if (signature->param_count) {
                int align, size;
 
                for (i = 0; i < signature->param_count; ++i) {
+                       int argvar;
                        size = mono_type_stack_size (signature->params [i], &align);
-                       arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
+                       argvar = arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
+                       VARINFO (cfg, argvar).isvolatile = 1;
                }
        }
 
@@ -2453,7 +2585,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        }
 
                        if (csig->hasthis) {
-                               this = *(--sp);                         
+                               this = *(--sp);         
                                args_size += sizeof (gpointer);
                        } else
                                this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
@@ -2686,6 +2818,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                        t1->data.i = LOCAL_POS (*ip);
+                       VARINFO (cfg, t1->data.i).isvolatile = 1;
                        ++ip;
                        PUSH_TREE (t1, VAL_POINTER);                    
                        break;
@@ -2971,7 +3104,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        if (sp > stack) {
                                g_warning ("more values on stack at IL_%04x: %d",  ip - header->code, sp - stack);
-                               mono_print_ctree (sp [-1]);
+                               mono_print_ctree (cfg, sp [-1]);
                                printf ("\n");
                        }
                        superblock_end = TRUE;
@@ -3263,6 +3396,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                                t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                                t1->data.i = LOCAL_POS (read16 (ip));
+                               VARINFO (cfg, t1->data.i).isvolatile = 1;
                                ip += 2;
                                PUSH_TREE (t1, VAL_POINTER);                    
                                break;
@@ -3398,14 +3532,14 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                cfg->invalid = 1;
                                return;
                        }
-                       mono_print_forest (forest);
+                       mono_print_forest (cfg, forest);
                        g_assert_not_reached ();
                }
        }               
 
         if ((depth = sp - stack)) {
                //printf ("DEPTH %d %d\n",  depth, sp [0]->op);
-               //mono_print_forest (forest);
+               //mono_print_forest (cfg, forest);
                create_outstack (cfg, bb, stack, sp - stack);
        }
 
@@ -3417,7 +3551,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                //printf ("unreached block %d\n", i);
                                repeat = TRUE;
                                if (repeat_count >= 10) {
-                                       /*mono_print_forest (forest);
+                                       /*mono_print_forest (cfg, forest);
                                        g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
                                        repeat = FALSE;
                                }
index 04f61c9647de0f08eb8e1f696a9985cbdc8ccd03..494427e28db1f28071230ca7610ad0e51a002635 100644 (file)
@@ -32,7 +32,7 @@
 
 #define ISSTRUCT(t) (!t->byref && t->type == MONO_TYPE_VALUETYPE && !t->data.klass->enumtype)
 
-#define VAROFFSET(cfg,num) (g_array_index (cfg->varinfo, MonoVarInfo, num).offset)
+#define VARINFO(cfg,num) (g_array_index (cfg->varinfo, MonoVarInfo, num))
 
 typedef struct _MBTree MBTree;
 
@@ -61,11 +61,27 @@ typedef struct {
        guint32     eip;
 } MonoLMF;
 
+typedef union {
+       struct {
+               guint16 tid; /* tree number */
+               guint16 bid; /* block number */
+       } pos ;
+       guint32 abs_pos; 
+} MonoPosition;
+
+typedef struct {
+       MonoPosition first_use, last_use;
+} MonoLiveRange;
+
 typedef struct {
        MonoValueType type;
        MonoValueKind kind;
        int offset;
        int size;
+       MonoLiveRange range;
+       unsigned isvolatile:1;
+       int reg;
+       int varnum; /* only for debugging */
 } MonoVarInfo;
 
 typedef struct {
@@ -73,6 +89,8 @@ typedef struct {
        unsigned is_block_start:1;
 } MonoBytecodeInfo;
 
+typedef guint32 * MonoBitSet;
+
 typedef struct {
        unsigned reached:1;
        unsigned finished:1;
@@ -85,6 +103,14 @@ typedef struct {
        MBTree      **outstack;
        gint32        outdepth;
        gint32        addr;
+       guint16       num;
+
+       MonoBitSet    gen_set;
+       MonoBitSet    kill_set;
+       MonoBitSet    live_in_set;
+       MonoBitSet    live_out_set;
+       
+       GList        *succ;
 } MonoBBlock;
 
 typedef enum {
@@ -177,6 +203,8 @@ extern gboolean mono_jit_trace_calls;
 extern gboolean mono_jit_profile;
 extern gboolean mono_jit_share_code;
 extern gboolean mono_jit_inline_code;
+extern gboolean mono_use_linear_scan;
+
 extern gpointer mono_end_of_stack;
 extern int      mono_worker_threads;
 extern guint32  lmf_thread_id;
@@ -238,6 +266,9 @@ int
 arch_allocate_var          (MonoFlowGraph *cfg, int size, int align, 
                            MonoValueKind kind, MonoValueType type);
 
+void
+mono_linear_scan           (MonoFlowGraph *cfg, guint32 *used_mask);
+
 /* delegate support functions */
 
 void
@@ -292,9 +323,9 @@ arch_method_return_message_restore (MonoMethod *method, gpointer stack,
 /* some handy debugging functions */
 
 void
-mono_print_ctree           (MBTree *tree);
+mono_print_ctree           (MonoFlowGraph *cfg, MBTree *tree);
 
 void
-mono_print_forest          (GPtrArray *forest);
+mono_print_forest          (MonoFlowGraph *cfg, GPtrArray *forest);
 
 #endif
diff --git a/mono/jit/linear-scan.c b/mono/jit/linear-scan.c
new file mode 100644 (file)
index 0000000..43366ff
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * linear-scan.c: linbear scan register allocation
+ *
+ * Authors:
+ *   Dietmar Maurer (dietmar@ximian.com)
+ *   Miguel de Icaza (miguel@ximian.com)
+ *
+ * (C) 2001 Ximian, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "jit.h"
+#include "codegen.h"
+#include "debug.h"
+
+//#define MNAME "nest_test"
+
+#ifdef MNAME
+#define DEGUG_LIVENESS
+#define DEBUG_LSCAN
+#endif
+
+inline static MonoBitSet
+mono_bitset_alloc (MonoFlowGraph *cfg, int n, gboolean use_mempool)
+{
+       if (use_mempool)
+               return (MonoBitSet)mono_mempool_alloc0 (cfg->mp, ((n + 31) >> 5) << 2);
+       else
+               return (MonoBitSet)g_malloc0 (((n + 31) >> 5) << 2);    
+}
+
+static void
+mono_bitset_set (MonoBitSet set, int n)
+{
+       int ind = n >> 5;
+       int pos = n & 0x1f;
+       set [ind] |= 1<<pos;
+}
+
+static gboolean
+mono_bitset_inset (MonoBitSet set, int n)
+{
+       int ind = n >> 5;
+       int pos = n & 0x1f;
+
+       if (set [ind] & (1<<pos))
+               return TRUE;
+
+       return FALSE;
+}
+
+static void
+mono_bitset_unset (MonoBitSet set, int n)
+{
+       int ind = n >> 5;
+       int pos = n & 0x1f;
+
+       set [ind] &= ~(1<<pos);
+}
+
+static void
+mono_bitset_add (MonoBitSet set1, MonoBitSet set2, int len)
+{
+       int i, ind = (len + 31) >> 5;
+       
+       for (i = 0; i < ind; i++)
+               set1 [i] |= set2 [i];
+}
+
+static void
+mono_bitset_sub (MonoBitSet set1, MonoBitSet set2, int len)
+{
+       int i, ind = (len + 31) >> 5;
+       
+       for (i = 0; i < ind; i++)
+               set1 [i] &= ~(set2 [i]);
+}
+
+static void
+mono_bitset_copy (MonoBitSet set1, MonoBitSet set2, int len)
+{
+       memcpy (set1, set2, (len + 7) >> 3);
+}
+
+static int
+mono_bitset_cmp (MonoBitSet set1, MonoBitSet set2, int len)
+{
+       return memcmp (set1, set2, (len + 7) >> 3);
+}
+
+static void
+mono_bitset_clear (MonoBitSet set, int len)
+{
+       memset (set, 0, (len + 7) >> 3);
+}
+
+static void
+mono_bitset_print (MonoBitSet set, int len)
+{
+       int i;
+
+       printf ("{");
+       for (i = 0; i < len; i++) {
+               int ind = i >> 5;
+               int pos = i & 0x1f;
+
+               if (set [ind] & (1<<pos))
+                       printf ("%d, ", i);
+
+       }
+       printf ("}");
+}
+
+static void
+update_live_range (MonoFlowGraph *cfg, int varnum, int block_num, int tree_pos)
+{
+       MonoVarInfo *vi = &g_array_index (cfg->varinfo, MonoVarInfo, varnum);
+       guint32 abs_pos = (block_num << 16) | tree_pos;
+
+       if (vi->range.first_use.abs_pos > abs_pos)
+               vi->range.first_use.abs_pos = abs_pos;
+
+       if (vi->range.last_use.abs_pos < abs_pos)
+               vi->range.last_use.abs_pos = abs_pos;
+}
+
+static void
+mono_update_live_info (MonoFlowGraph *cfg)
+{
+       int i, j;
+
+       for (i = 0; i < cfg->block_count; i++) {
+               MonoBBlock *bb = &cfg->bblocks [i];
+
+               for (j = cfg->varinfo->len; j > 0; j--) {
+                       
+                       if (mono_bitset_inset (bb->live_in_set, j))
+                               update_live_range (cfg, j, bb->num, 0);
+
+                       if (mono_bitset_inset (bb->live_out_set, j))
+                               update_live_range (cfg, j, bb->num, bb->forest->len);
+               } 
+       } 
+}
+
+static void
+update_tree_live_info (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree *tree)
+{
+       if (tree->left)
+               update_tree_live_info (cfg, bb, tree->left);
+       if (tree->right)
+               update_tree_live_info (cfg, bb, tree->right);
+
+       if (tree->op == MB_TERM_ADDR_L)
+               update_live_range (cfg, tree->data.i, bb->num, bb->forest->len); 
+} 
+
+static void
+update_gen_set (MBTree *tree, MonoBitSet set)
+{
+       if (tree->left) {
+               switch (tree->op) {
+               case MB_TERM_REMOTE_STIND_I1:
+               case MB_TERM_REMOTE_STIND_I2:
+               case MB_TERM_REMOTE_STIND_I4:
+               case MB_TERM_REMOTE_STIND_I8:
+               case MB_TERM_REMOTE_STIND_R4:
+               case MB_TERM_REMOTE_STIND_R8:
+               case MB_TERM_REMOTE_STIND_REF:
+               case MB_TERM_REMOTE_STIND_OBJ:
+               case MB_TERM_STIND_I1:
+               case MB_TERM_STIND_I2:
+               case MB_TERM_STIND_I4:
+               case MB_TERM_STIND_I8:
+               case MB_TERM_STIND_R4:
+               case MB_TERM_STIND_R8:
+               case MB_TERM_STIND_REF:
+               case MB_TERM_STIND_OBJ:
+                       if (tree->left->op != MB_TERM_ADDR_L)
+                               update_gen_set (tree->left, set);
+                               break;
+               default:
+                       update_gen_set (tree->left, set);
+                       break;
+               }
+       }
+
+       if (tree->right)
+               update_gen_set (tree->right, set);
+
+       if (tree->op == MB_TERM_ADDR_L) 
+               mono_bitset_set (set, tree->data.i);
+} 
+
+static void
+mono_analyze_liveness (MonoFlowGraph *cfg)
+{
+       MonoBitSet old_live_in_set, old_live_out_set;
+       gboolean changes;
+       GList *l;
+       int i, j , max_vars = cfg->varinfo->len;
+
+#ifdef DEGUG_LIVENESS
+       int debug = !strcmp (cfg->method->name, MNAME);
+       if (debug)
+               printf ("LIVENLESS %s.%s:%s\n", cfg->method->klass->name_space,
+                       cfg->method->klass->name, cfg->method->name);
+#endif
+
+       old_live_in_set = mono_bitset_alloc (cfg, max_vars, FALSE);
+       old_live_out_set = mono_bitset_alloc (cfg, max_vars, FALSE);
+
+       for (i = 0; i < cfg->block_count; i++) {
+               MonoBBlock *bb = &cfg->bblocks [i];
+
+               bb->gen_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+               bb->kill_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+               bb->live_in_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+               bb->live_out_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+
+               for (j = 0; j < bb->forest->len; j++) {
+                       MBTree *t1 = (MBTree *) g_ptr_array_index (bb->forest, j);
+
+                       update_tree_live_info (cfg, bb, t1);
+
+                       mono_bitset_clear (old_live_in_set, max_vars);
+                       update_gen_set (t1, old_live_in_set);
+                       mono_bitset_sub (old_live_in_set, bb->kill_set, max_vars);
+                       mono_bitset_add (bb->gen_set, old_live_in_set, max_vars);
+
+                       switch (t1->op) {
+                       case MB_TERM_REMOTE_STIND_I1:
+                       case MB_TERM_REMOTE_STIND_I2:
+                       case MB_TERM_REMOTE_STIND_I4:
+                       case MB_TERM_REMOTE_STIND_I8:
+                       case MB_TERM_REMOTE_STIND_R4:
+                       case MB_TERM_REMOTE_STIND_R8:
+                       case MB_TERM_REMOTE_STIND_REF:
+                       case MB_TERM_REMOTE_STIND_OBJ:
+                       case MB_TERM_STIND_I1:
+                       case MB_TERM_STIND_I2:
+                       case MB_TERM_STIND_I4:
+                       case MB_TERM_STIND_I8:
+                       case MB_TERM_STIND_R4:
+                       case MB_TERM_STIND_R8:
+                       case MB_TERM_STIND_REF:
+                       case MB_TERM_STIND_OBJ:
+                               if (t1->left->op == MB_TERM_ADDR_L)
+                                       mono_bitset_set (bb->kill_set, t1->left->data.i);
+                               break;
+                       }
+               }
+
+#ifdef DEGUG_LIVENESS
+               if (debug) {
+                       printf ("BLOCK %d (", bb->num);
+                       for (l = bb->succ; l; l = l->next) {
+                               MonoBBlock *t = (MonoBBlock *)l->data;
+                               printf ("%d, ", t->num);
+                       }
+                       printf (")\n");
+                       printf ("GEN  %d: ", i); mono_bitset_print (bb->gen_set, max_vars); printf ("\n");
+                       printf ("KILL %d: ", i); mono_bitset_print (bb->kill_set, max_vars); printf ("\n");
+               }
+#endif
+       }
+       
+       do {
+               changes = FALSE;
+               for (i = 0; i < cfg->block_count; i++) {
+                       MonoBBlock *bb = &cfg->bblocks [i];
+
+                       mono_bitset_copy (old_live_in_set, bb->live_in_set, max_vars);
+                       mono_bitset_copy (old_live_out_set, bb->live_out_set, max_vars);
+
+                       mono_bitset_copy (bb->live_in_set, bb->live_out_set, max_vars);
+                       mono_bitset_sub (bb->live_in_set, bb->kill_set, max_vars);
+                       mono_bitset_add (bb->live_in_set, bb->gen_set, max_vars);
+
+                       mono_bitset_clear (bb->live_out_set, max_vars);
+                       
+                       for (l = bb->succ; l; l = l->next) {
+                               MonoBBlock *t = (MonoBBlock *)l->data;
+                               mono_bitset_add (bb->live_out_set, t->live_in_set, max_vars);
+                       }
+
+                       if (mono_bitset_cmp (old_live_in_set, bb->live_in_set, max_vars) ||
+                           mono_bitset_cmp (old_live_out_set, bb->live_out_set, max_vars))
+                               changes = TRUE;
+                           
+               }
+
+       } while (changes);
+
+       g_free (old_live_in_set);
+       g_free (old_live_out_set);
+
+
+#ifdef DEGUG_LIVENESS
+       if (debug) {
+               for (i = 0; i < cfg->block_count; i++) {
+                       MonoBBlock *bb = &cfg->bblocks [i];
+               
+                       printf ("LIVE IN  %d: ", i); 
+                       mono_bitset_print (bb->live_in_set, max_vars); 
+                       printf ("\n");
+                       printf ("LIVE OUT %d: ", i); 
+                       mono_bitset_print (bb->live_out_set, max_vars); 
+                       printf ("\n");
+               }
+       }
+#endif
+}
+
+static GList *
+mono_varlist_insert_sorted (GList *list, MonoVarInfo *vi, gboolean sort_end)
+{
+       GList *l;
+
+       if (!list)
+               return g_list_prepend (NULL, vi);
+
+       for (l = list; l; l = l->next) {
+               MonoVarInfo *v = (MonoVarInfo *)l->data;
+               
+               if (sort_end) {
+                       if (vi->range.last_use.abs_pos <= v->range.last_use.abs_pos) {
+                               list = g_list_insert_before (list, l, vi);
+                               break;
+                       }
+               } else {
+                       if (vi->range.first_use.abs_pos <= v->range.first_use.abs_pos) {
+                               list = g_list_insert_before (list, l, vi);
+                               break;
+                       }
+               }
+       }
+       if (!l)
+               list = g_list_append (list, vi);
+
+       return list;
+}
+
+void
+mono_linear_scan (MonoFlowGraph *cfg, guint32 *used_mask)
+{
+       GList *l, *ranges = NULL;
+       GList *active = NULL;
+       GList *regs = NULL;
+       int i, max_regs;
+
+#ifdef DEBUG_LSCAN
+       MonoMethod *m = cfg->method;
+       int debug = !strcmp (cfg->method->name, MNAME);
+
+       if (debug)
+               printf ("VARINFO for %s.%s:%s\n", m->klass->name_space, m->klass->name, m->name);
+#endif
+
+       mono_analyze_liveness (cfg);
+       mono_update_live_info (cfg);
+
+       for (i = 1; i < cfg->varinfo->len; i++) {
+               MonoVarInfo *vi = &g_array_index (cfg->varinfo, MonoVarInfo, i);
+
+               /* unused vars */
+               if (vi->range.first_use.abs_pos > vi->range.last_use.abs_pos)
+                       continue;
+
+               /* we can only allocate 32 bit values */
+               if (vi->isvolatile || (vi->type != VAL_I32 && vi->type != VAL_POINTER))
+                       continue;
+
+               ranges = mono_varlist_insert_sorted (ranges, vi, FALSE);
+
+       }
+
+#ifdef DEBUG_LSCAN
+       if (debug) {
+               for (l = ranges; l; l = l->next) {
+                       MonoVarInfo *vi = (MonoVarInfo *)l->data;
+
+                       printf ("VAR %d %08x %08x\n", vi->varnum, vi->range.first_use.abs_pos,  
+                               vi->range.last_use.abs_pos);
+               }
+       }
+#endif
+       
+       /* we can use 2 registers for global allocation */
+       regs = g_list_prepend (regs, (gpointer)X86_EBX);
+       regs = g_list_prepend (regs, (gpointer)X86_ESI);
+
+       max_regs = g_list_length (regs);
+
+       /* linear scan */
+
+       for (l = ranges; l; l = l->next) {
+               MonoVarInfo *vi = (MonoVarInfo *)l->data;
+
+#ifdef DEBUG_LSCAN
+               if (debug)
+                       printf ("START  %2d %08x %08x\n",  vi->varnum, vi->range.first_use.abs_pos, 
+                               vi->range.last_use.abs_pos);
+#endif
+               /* expire old intervals in active */
+               while (active) {
+                       MonoVarInfo *v = (MonoVarInfo *)active->data;
+
+                       if (v->range.last_use.abs_pos >= vi->range.first_use.abs_pos)
+                               break;
+
+#ifdef DEBUG_LSCAN
+                       if (debug)
+                               printf ("EXPIR  %2d %08x %08x\n",  v->varnum, 
+                                       v->range.first_use.abs_pos, v->range.last_use.abs_pos);
+#endif
+                       active = g_list_remove_link (active, active);
+                       regs = g_list_prepend (regs, (gpointer)v->reg);
+               }
+               
+               if (active && g_list_length (active) == max_regs) {
+                       /* Spill */
+                       
+                       GList *a = g_list_nth (active, max_regs - 1);
+                       MonoVarInfo *v = (MonoVarInfo *)a->data;
+
+                       if (v->range.last_use.abs_pos > vi->range.last_use.abs_pos) {
+                               vi->reg = v->reg;
+                               v->reg = -1;
+                               active = g_list_remove_link (active, a);
+                               active = mono_varlist_insert_sorted (active, vi, TRUE);         
+#ifdef DEBUG_LSCAN
+                               if (debug)
+                                       printf ("SPILL0 %2d %08x %08x\n",  v->varnum, 
+                                               v->range.first_use.abs_pos, v->range.last_use.abs_pos);
+#endif
+                       } else {
+#ifdef DEBUG_LSCAN
+                               if (debug)
+                                       printf ("SPILL1 %2d %08x %08x\n",  vi->varnum, 
+                                               vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
+#endif
+                               vi->reg = -1;
+                       }
+               } else {
+                       /* assign register */
+
+                       g_assert (regs);
+
+                       vi->reg = (int)regs->data;
+
+                       *used_mask |= 1 << vi->reg;
+
+                       regs = g_list_remove_link (regs, regs);
+
+#ifdef DEBUG_LSCAN
+                       if (debug)
+                               printf ("ADD    %2d %08x %08x\n",  vi->varnum, 
+                                       vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
+#endif
+                       active = mono_varlist_insert_sorted (active, vi, TRUE);         
+               }
+
+
+#ifdef DEBUG_LSCAN
+               if (debug) {
+                       GList *a;
+                       for (a = active; a; a = a->next) {
+                               MonoVarInfo *v = (MonoVarInfo *)a->data;
+                            
+                               printf ("ACT    %2d %08x %08x %d\n", v->varnum, 
+                                       v->range.first_use.abs_pos,  v->range.last_use.abs_pos, v->reg);
+                       }
+                       printf ("NEXT\n");
+               }
+#endif
+       }       
+
+       g_list_free (regs);
+       g_list_free (active);
+       g_list_free (ranges);
+
+}
+
index 59fec4710f3f25af5ba2d854ab165c99125d9d52..67cb7b4c76401990ee580b5c0689491ac9342488 100644 (file)
@@ -60,6 +60,7 @@ usage (char *name)
                 "--dwarf-plus     write extended dwarf2 debug information\n"
                 "--stats          print statistics about the jit operations\n"
                 "--noinline       do not inline code\n"
+                "--ls             use linear scan register allocation\n"
                 "--compile cname  compile methods in given class (namespace.name[:methodname])\n"
                 "--ncompile num   compile methods num times (default: 1000)\n"
                 "--debug name     insert a breakpoint at the start of method name\n"
@@ -105,6 +106,8 @@ main (int argc, char *argv [])
                        mono_jit_share_code = TRUE;
                else if (strcmp (argv [i], "--noinline") == 0)
                        mono_jit_inline_code = FALSE;
+               else if (strcmp (argv [i], "--ls") == 0)
+                       mono_use_linear_scan = TRUE;
                else if (strcmp (argv [i], "--print-vtable") == 0)
                        mono_print_vtable = TRUE;
                else if (strcmp (argv [i], "--debug") == 0) {
index 8b0a175346433fd04ef9444227e04607bc05a407..752b19c3650f24f15eb4ebc7a9d07c915fd6ed1d 100644 (file)
@@ -218,7 +218,6 @@ arch_create_jit_trampoline (MonoMethod *method)
 
        if (!vc) {
                vc = buf = g_malloc (256);
-
                /* save caller save regs because we need to do a call */ 
                x86_push_reg (buf, X86_EDX);
                x86_push_reg (buf, X86_EAX);
index 510f26fb57a6d62bc402b162dcd5d8b1ee59c4b8..e60f75847fcda1cedad4a52e119390780c3f6cdf 100644 (file)
@@ -147,7 +147,7 @@ x86_call_reg (s->code, X86_EAX); \
 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 3*4); \
 x86_pop_reg (s->code, X86_ECX); \
 x86_pop_reg (s->code, X86_EDX); \
-x86_pop_reg (s->code, X86_EAX); 
+x86_pop_reg (s->code, X86_EAX);
 
 #ifdef DEBUG
 #define MEMCOPY debug_memcpy
@@ -329,9 +329,12 @@ base: ADD (reg, coni4) {
 }
 
 base: ADDR_L {
-       tree->data.ainfo.offset = VAROFFSET (s, tree->data.i);
+       tree->data.ainfo.offset = VARINFO (s, tree->data.i).offset;
        tree->data.ainfo.basereg = X86_EBP;
        tree->data.ainfo.amode = AMBase;
+} cost {
+       MBCOND (VARINFO (data, tree->data.i).reg < 0);
+       return 0;
 }
 
 index: reg {
@@ -386,7 +389,7 @@ addr: ADD (index, base) {
 
 # we pass exception in ECX to catch handler
 reg: EXCEPTION {
-       int offset = VAROFFSET (s, tree->data.i);
+       int offset = VARINFO (s, tree->data.i).offset;
 
        if (tree->reg1 != X86_ECX)
                x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
@@ -405,7 +408,7 @@ stmt: THROW (reg) {
 }
 
 stmt: RETHROW {
-       int off = VAROFFSET (s, tree->data.i);
+       int off = VARINFO (s, tree->data.i).offset;
        gpointer target;
 
        x86_push_membase (s->code, X86_EBP, off);
@@ -711,6 +714,82 @@ stmt: REMOTE_STIND_I2 (reg, reg) {
        x86_patch (br [1], s->code);
 }
 
+stmt: STIND_I4 (ADDR_L, reg) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       if (treg != tree->right->reg1)
+               x86_mov_reg_reg (s->code, treg, tree->right->reg1, 4);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
+stmt: STIND_I4 (ADDR_L, coni4) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       x86_mov_reg_imm (s->code, treg, tree->right->data.i);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
+reg: LDIND_I4 (ADDR_L) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       if (treg != tree->reg1)
+               x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
+reg: LDIND_U4 (ADDR_L) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       if (treg != tree->reg1)
+               x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
+stmt: STIND_REF (ADDR_L, reg) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       if (treg != tree->right->reg1)
+               x86_mov_reg_reg (s->code, treg, tree->right->reg1, 4);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
+stmt: STIND_REF (ADDR_L, coni4) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       if (treg != tree->right->reg1)
+               x86_mov_reg_imm (s->code, treg, tree->right->data.i);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
+reg: LDIND_REF (ADDR_L) {
+       int treg = VARINFO (s, tree->left->data.i).reg;
+
+       if (treg != tree->reg1)
+               x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
+
+} cost {
+       MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+       return 0;
+}
+
 reg: LDIND_I4 (addr) {
 
        switch (tree->left->data.ainfo.amode) {
@@ -946,12 +1025,15 @@ reg: REMOTE_LDFLDA (reg) {
                x86_pop_reg (s->code, treg);
 }
 
-reg: ADDR_L {
-       int offset = VAROFFSET (s, tree->data.i);  
+reg: ADDR_L {
+       int offset = VARINFO (s, tree->data.i).offset;  
 
        x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
        
        PRINT_REG ("ADDR_L",  tree->reg1);
+} cost {
+       MBCOND (VARINFO (data, tree->data.i).reg < 0);
+       return 5;
 }
 
 
@@ -1909,51 +1991,6 @@ cflags: COMPARE (reg, coni4) {
        x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
 }
 
-cflags: COMPARE (LDIND_I4 (ADDR_L), coni4) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->left->left->data.i);  
-       x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, tree->right->data.i);
-}
-
-cflags: COMPARE (LDIND_U4 (ADDR_L), coni4) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->left->left->data.i);  
-       x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, tree->right->data.i);
-}
-
-cflags: COMPARE (LDIND_REF (ADDR_L), coni4) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->left->left->data.i);  
-       x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, tree->right->data.i);
-}
-
-cflags: COMPARE (reg, LDIND_I4 (ADDR_L)) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->right->left->data.i);  
-       x86_alu_reg_membase (s->code, X86_CMP, tree->left->reg1, X86_EBP, offset);
-}
-
-cflags: COMPARE (reg, LDIND_U4 (ADDR_L)) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->right->left->data.i);  
-       x86_alu_reg_membase (s->code, X86_CMP, tree->left->reg1, X86_EBP, offset);
-}
-
-cflags: COMPARE (reg, LDIND_REF (ADDR_L)) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->right->left->data.i);  
-       x86_alu_reg_membase (s->code, X86_CMP, tree->left->reg1, X86_EBP, offset);
-}
-
-cflags: COMPARE (LDIND_I4 (ADDR_L), reg) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->left->left->data.i);  
-       x86_alu_membase_reg (s->code, X86_CMP, X86_EBP, offset, tree->right->reg1);
-}
-
-cflags: COMPARE (LDIND_U4 (ADDR_L), reg) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->left->left->data.i);  
-       x86_alu_membase_reg (s->code, X86_CMP, X86_EBP, offset, tree->right->reg1);
-}
-
-cflags: COMPARE (LDIND_REF (ADDR_L), reg) "MB_USE_OPT1(0)" {
-       int offset = VAROFFSET (s, tree->left->left->data.i);  
-       x86_alu_membase_reg (s->code, X86_CMP, X86_EBP, offset, tree->right->reg1);
-}
-
 cflags: COMPARE (reg, reg) {
        x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
 }
@@ -2148,7 +2185,7 @@ reg: CALL_I4 (this, reg) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2177,7 +2214,7 @@ reg: CALL_I4 (this, ADDR_G) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2216,7 +2253,7 @@ reg: CALL_I4 (this, INTF_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2277,7 +2314,7 @@ reg: CALL_I4 (this, VFUNC_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2308,7 +2345,7 @@ stmt: CALL_VOID (this, ADDR_G) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2333,7 +2370,7 @@ stmt: CALL_VOID (this, INTF_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2361,7 +2398,7 @@ stmt: CALL_VOID (this, VFUNC_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -2618,7 +2655,6 @@ stmt: STIND_I8 (addr, lreg) {
                                      tree->right->reg2, 4);
                break;          
        }
-
 }
 
 stmt: REMOTE_STIND_I8 (reg, lreg) {
@@ -3043,7 +3079,7 @@ lreg: CALL_I8 (this, ADDR_G) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -3071,7 +3107,7 @@ lreg: CALL_I8 (this, VFUNC_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -3103,7 +3139,7 @@ lreg: CALL_I8 (this, INTF_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -3641,7 +3677,7 @@ freg: NEG (freg) {
 stmt: POP (freg)
 
 stmt: STIND_R4 (ADDR_L, freg) {
-       int offset = VAROFFSET (s, tree->left->data.i);  
+       int offset = VARINFO (s, tree->left->data.i).offset;  
        x86_fst_membase (s->code, X86_EBP, offset, FALSE, TRUE);
 }
 
@@ -3687,7 +3723,7 @@ stmt: REMOTE_STIND_R4 (reg, freg) {
 }
 
 stmt: STIND_R8 (ADDR_L, freg) {
-       int offset = VAROFFSET (s, tree->left->data.i);  
+       int offset = VARINFO (s, tree->left->data.i).offset;  
        x86_fst_membase (s->code, X86_EBP, offset, TRUE, TRUE);
 }
 
@@ -3816,7 +3852,7 @@ freg: CALL_R8 (this, ADDR_G) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -3841,7 +3877,7 @@ freg: CALL_R8 (this, INTF_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -3869,7 +3905,7 @@ freg: CALL_R8 (this, VFUNC_ADDR) {
        }
 
        if (tree->data.ci.vtype_num) {
-               int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
                x86_lea_membase (s->code, treg, X86_EBP, offset);
                x86_push_reg (s->code, treg);
        }
@@ -3898,6 +3934,7 @@ reg: LDIND_OBJ (reg) {
 
 stmt: STIND_OBJ (reg, reg) {
        mono_assert (tree->data.i > 0);
+
        x86_push_imm (s->code, tree->data.i);
        x86_push_reg (s->code, tree->right->reg1);
        x86_push_reg (s->code, tree->left->reg1);