2009-02-03 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Tue, 3 Feb 2009 16:34:38 +0000 (16:34 -0000)
committerZoltan Varga <vargaz@gmail.com>
Tue, 3 Feb 2009 16:34:38 +0000 (16:34 -0000)
* mini-amd64.c (mono_arch_output_basic_block): Add OP_LIVERANGE_START/END.

* method-to-ir.c (mono_spill_global_vars): Compute the instructions marking
the live ranges of variables, and emit OP_LIVERANGE_START/END opcodes for
them.

* mini-ops.h: Add OP_LIVERANGE_START/END opcodes to mark
the live ranges of variables.

* mini.h (struct MonoMethodVar): Add two fields containing the live range
of the variable in terms of native offsets.

svn path=/trunk/mono/; revision=125543

mono/mini/ChangeLog
mono/mini/cpu-amd64.md
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-amd64.h
mono/mini/mini-ops.h
mono/mini/mini.h

index d1724b8ae74d0f983fde798ac1a470864f431399..349fae6037bdcb3033d6163a22d2d403c0c7f1f2 100644 (file)
@@ -1,3 +1,17 @@
+2009-02-03  Zoltan Varga  <vargaz@gmail.com>
+
+       * mini-amd64.c (mono_arch_output_basic_block): Add OP_LIVERANGE_START/END.
+
+       * method-to-ir.c (mono_spill_global_vars): Compute the instructions marking
+       the live ranges of variables, and emit OP_LIVERANGE_START/END opcodes for
+       them.
+
+       * mini-ops.h: Add OP_LIVERANGE_START/END opcodes to mark
+       the live ranges of variables.
+
+       * mini.h (struct MonoMethodVar): Add two fields containing the live range
+       of the variable in terms of native offsets.
+
 2009-02-03  Rodrigo Kumpera  <rkumpera@novell.com>
 
        * arrays.cs: Test for Get/SetValue of array with negate lower bounds.
index d3a2d0fe1d574a3d910f958008b06539f1b4ef90..db0be21bb2aa016d0fae8f80a42af28b2c8db406 100644 (file)
@@ -502,3 +502,6 @@ loadi8_mem: dest:i len:16
 loadi4_mem: dest:i len:16
 loadu1_mem: dest:i len:16
 loadu2_mem: dest:i len:16
+
+liverange_start: len:0
+liverange_end: len:0
index 021c5d9cf36e7efb9ff822f40b6c696cc2178f7d..cbf9976448da9fb33d8ad80bea16b1dfbeef47bf 100644 (file)
@@ -10239,6 +10239,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        guint32 i, lvregs_len;
        gboolean dest_has_lvreg = FALSE;
        guint32 stacktypes [128];
+       MonoInst **live_range_start, **live_range_end;
+       MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
 
        *need_local_opts = FALSE;
 
@@ -10298,6 +10300,20 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
        lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
        lvregs_len = 0;
+
+       /* 
+        * These arrays contain the first and last instructions accessing a given
+        * variable.
+        * Since we emit bblocks in the same order we process them here, and we
+        * don't split live ranges, these will precisely describe the live range of
+        * the variable, i.e. the instruction range where a valid value can be found
+        * in the variables location.
+        */
+       /* FIXME: Only do this if debugging info is requested */
+       live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
+       live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
+       live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
+       live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
        
        /* Add spill loads/stores */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -10395,6 +10411,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
                                MonoInst *store_ins;
                                int store_opcode;
+                               MonoInst *def_ins = ins;
 
                                store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
 
@@ -10407,6 +10424,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        g_assert (var->opcode == OP_REGOFFSET);
                                        if (ins->opcode == OP_MOVE) {
                                                NULLIFY_INS (ins);
+                                               def_ins = NULL;
                                        } else {
                                                ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
                                                ins->inst_basereg = var->inst_basereg;
@@ -10440,6 +10458,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
                                                NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
+                                               def_ins = store_ins;
                                        }
                                        else {
                                                g_assert (store_opcode != OP_STOREV_MEMBASE);
@@ -10482,6 +10501,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        /* Insert it after the instruction */
                                                        mono_bblock_insert_after_ins (bb, ins, store_ins);
 
+                                                       def_ins = store_ins;
+
                                                        /* 
                                                         * We can't assign ins->dreg to var->dreg here, since the
                                                         * sregs could use it. So set a flag, and do it after
@@ -10492,6 +10513,11 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                }
                                        }
                                }
+
+                               if (def_ins && !live_range_start [var->dreg]) {
+                                       live_range_start [var->dreg] = def_ins;
+                                       live_range_start_bb [var->dreg] = bb;
+                               }
                        }
 
                        /************/
@@ -10504,6 +10530,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
                                if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
                                        MonoInst *var = get_vreg_to_inst (cfg, sreg);
+                                       MonoInst *use_ins = ins;
                                        MonoInst *load_ins;
                                        guint32 load_opcode;
 
@@ -10512,6 +10539,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        ins->sreg1 = var->dreg;
                                                else
                                                        ins->sreg2 = var->dreg;
+                                               live_range_end [var->dreg] = use_ins;
+                                               live_range_end_bb [var->dreg] = bb;
                                                continue;
                                        }
 
@@ -10575,6 +10604,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
+                                                       use_ins = load_ins;
                                                }
                                                else {
 #if SIZEOF_REGISTER == 4
@@ -10582,8 +10612,12 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
 #endif
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
+                                                       use_ins = load_ins;
                                                }
                                        }
+
+                                       live_range_end [var->dreg] = use_ins;
+                                       live_range_end_bb [var->dreg] = bb;
                                }
                        }
 
@@ -10611,6 +10645,36 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                mono_print_ins_index (1, ins);
                }
        }
+
+       cfg->vreg_to_var_num = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32) * cfg->next_vreg);
+       for (i = 0; i < cfg->num_varinfo; ++i)
+               cfg->vreg_to_var_num [cfg->varinfo [i]->dreg] = i;
+       
+#ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
+       /*
+        * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
+        * by storing the current native offset into MonoMethodVar->live_range_start/end.
+        */
+       for (i = 0; i < orig_next_vreg; ++i) {
+               MonoInst *ins;
+
+               if (live_range_start [i]) {
+                       MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
+                       ins->inst_c0 = cfg->vreg_to_var_num [i];
+                       mono_bblock_insert_after_ins (live_range_start_bb [i], live_range_start [i], ins);
+               }
+               if (live_range_end [i]) {
+                       MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
+                       ins->inst_c0 = cfg->vreg_to_var_num [i];
+                       mono_bblock_insert_after_ins (live_range_end_bb [i], live_range_end [i], ins);
+               }
+       }
+#endif
+
+       g_free (live_range_start);
+       g_free (live_range_end);
+       g_free (live_range_start_bb);
+       g_free (live_range_end_bb);
 }
 
 /**
index 55e32f27e9f58baa5ff6474dc12a887daa62511d..66041a573eafd3710f591100f0555322c9096b9e 100644 (file)
@@ -4251,6 +4251,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        break;
                }
+               case OP_LIVERANGE_START: {
+                       if (cfg->verbose_level > 1)
+                               printf ("R%d START=0x%x\n", cfg->varinfo [ins->inst_c0]->dreg, (int)(code - cfg->native_code));
+                       MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
+                       break;
+               }
+               case OP_LIVERANGE_END: {
+                       if (cfg->verbose_level > 1)
+                               printf ("R%d END=0x%x\n", cfg->varinfo [ins->inst_c0]->dreg, (int)(code - cfg->native_code));
+                       MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
+                       break;
+               }
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
                        g_assert_not_reached ();
index 86f111f7665db5550de0058f0419c4fe35476628..a52eb2d07afe29d8cc2b6e0cbc59e81946f5862d 100644 (file)
@@ -319,6 +319,7 @@ typedef struct {
 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
 #define MONO_ARCH_ENABLE_GLOBAL_RA 1
 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
+#define MONO_ARCH_HAVE_LIVERANGE_OPS 1
 #if !defined(PLATFORM_WIN32) && !defined(HAVE_MOVING_COLLECTOR)
 #define MONO_ARCH_MONITOR_OBJECT_REG AMD64_RDI
 #endif
index e1eb611fadb9946befad9aca768f80cd56b33ed3..246e91711409d868fa2273da4ccecbf815a03ba7 100644 (file)
@@ -835,6 +835,18 @@ MINI_OP(OP_CMOV_LGT_UN, "cmov_lgt_un", IREG, IREG, IREG)
 MINI_OP(OP_CMOV_LLE_UN, "cmov_lle_un", IREG, IREG, IREG)
 MINI_OP(OP_CMOV_LLT_UN, "cmov_llt_un", IREG, IREG, IREG)
 
+/* Debugging support */
+/* 
+ * Marks the start of the live range of the variable in inst_c0, that is the
+ * first instruction where the variable has a value.
+ */
+MINI_OP(OP_LIVERANGE_START, "liverange_start", NONE, NONE, NONE)
+/* 
+ * Marks the end of the live range of the variable in inst_c0, that is the
+ * first instruction where the variable no longer has a value.
+ */
+MINI_OP(OP_LIVERANGE_END, "liverange_end", NONE, NONE, NONE)
+
 /* Arch specific opcodes */
 #if defined(__i386__) || defined(__x86_64__)
 MINI_OP(OP_X86_TEST_NULL,          "x86_test_null", NONE, NONE, NONE)
index 3635a438e34de856a534d246fffb77adc6e9e8ae..086167be2ae803fce1bee37352ff89977983989a 100644 (file)
@@ -615,6 +615,8 @@ struct MonoMethodVar {
        MonoBasicBlock *def_bb; /* used by SSA */
        GList          *uses;   /* used by SSA */
        char            cpstate;  /* used by SSA conditional  constant propagation */
+       /* The native offsets corresponding to the live range of the variable */
+       gint32         live_range_start, live_range_end;
 };
 
 typedef struct {
@@ -883,6 +885,12 @@ typedef struct {
        /* Size of above array */
        guint32 vreg_to_inst_len;
 
+       /* Maps global vregs to the indexes in the cfg->vars array */
+       gint32 *vreg_to_var_num;
+
+       /* Size of above array */
+       guint32 vreg_to_var_index_num;
+
        /* 
         * The original method to compile, differs from 'method' when doing generic
         * sharing.