2008-11-16 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / liveness.c
1 /*
2  * liveness.c: liveness analysis
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include "mini.h"
11 #include "inssel.h"
12 #include "aliasing.h"
13
14 #define SPILL_COST_INCREMENT (1 << (bb->nesting << 1))
15
16 //#define DEBUG_LIVENESS
17
18 #if SIZEOF_VOID_P == 8
19 #define BITS_PER_CHUNK 64
20 #else
21 #define BITS_PER_CHUNK 32
22 #endif
23
24 /* 
25  * The liveness2 pass can't handle long vars on 32 bit platforms because the component
26  * vars have the same 'idx'.
27  */
28 #if SIZEOF_VOID_P == 8
29 #define ENABLE_LIVENESS2
30 #endif
31
32 #ifdef ENABLE_LIVENESS2
33 static void mono_analyze_liveness2 (MonoCompile *cfg);
34 #endif
35
36 static void
37 optimize_initlocals (MonoCompile *cfg);
38
39 /* mono_bitset_mp_new:
40  * 
41  * allocates a MonoBitSet inside a memory pool
42  */
43 static inline MonoBitSet* 
44 mono_bitset_mp_new (MonoMemPool *mp, guint32 size, guint32 max_size)
45 {
46         guint8 *mem = mono_mempool_alloc0 (mp, size);
47         return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
48 }
49
50 static inline MonoBitSet* 
51 mono_bitset_mp_new_noinit (MonoMemPool *mp, guint32 size, guint32 max_size)
52 {
53         guint8 *mem = mono_mempool_alloc (mp, size);
54         return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
55 }
56
57 G_GNUC_UNUSED static void
58 mono_bitset_print (MonoBitSet *set)
59 {
60         int i;
61
62         printf ("{");
63         for (i = 0; i < mono_bitset_size (set); i++) {
64
65                 if (mono_bitset_test (set, i))
66                         printf ("%d, ", i);
67
68         }
69         printf ("}\n");
70 }
71
72 static void
73 visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, GSList **visited)
74 {
75         int i;
76         MonoInst *ins;
77
78         if (g_slist_find (*visited, bb))
79                 return;
80
81         for (ins = bb->code; ins; ins = ins->next) {
82                 const char *spec = INS_INFO (ins->opcode);
83                 int regtype, srcindex, sreg;
84
85                 if (ins->opcode == OP_NOP)
86                         continue;
87
88                 /* DREG */
89                 regtype = spec [MONO_INST_DEST];
90                 g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
91                                 
92                 if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
93                         MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
94                         int idx = var->inst_c0;
95                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
96
97                         cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
98                 }
99                         
100                 /* SREGS */
101                 for (srcindex = 0; srcindex < 2; ++srcindex) {
102                         regtype = spec [(srcindex == 0) ? MONO_INST_SRC1 : MONO_INST_SRC2];
103                         sreg = srcindex == 0 ? ins->sreg1 : ins->sreg2;
104                         
105                         g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
106                         if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
107                                 MonoInst *var = get_vreg_to_inst (cfg, sreg);
108                                 int idx = var->inst_c0;
109                                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
110
111                                 cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
112                         }
113                 }
114         }
115
116         *visited = g_slist_append (*visited, bb);
117
118         /* 
119          * Need to visit all bblocks reachable from this one since they can be
120          * reached during exception handling.
121          */
122         for (i = 0; i < bb->out_count; ++i) {
123                 visit_bb (cfg, bb->out_bb [i], visited);
124         }
125 }
126
127 void
128 mono_liveness_handle_exception_clauses (MonoCompile *cfg)
129 {
130         MonoBasicBlock *bb;
131         GSList *visited = NULL;
132
133         /*
134          * Variables in exception handler register cannot be allocated to registers
135          * so make them volatile. See bug #42136. This will not be neccessary when
136          * the back ends could guarantee that the variables will be in the
137          * correct registers when a handler is called.
138          * This includes try blocks too, since a variable in a try block might be
139          * accessed after an exception handler has been run.
140          */
141         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
142
143                 if (bb->region == -1 || MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))
144                         continue;
145
146                 visit_bb (cfg, bb, &visited);
147         }
148         g_slist_free (visited);
149 }
150
151 static inline void
152 update_live_range (MonoMethodVar *var, int abs_pos)
153 {
154         if (var->range.first_use.abs_pos > abs_pos)
155                 var->range.first_use.abs_pos = abs_pos;
156
157         if (var->range.last_use.abs_pos < abs_pos)
158                 var->range.last_use.abs_pos = abs_pos;
159 }
160
161 static void
162 analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb)
163 {
164         MonoInst *ins;
165         int sreg, inst_num;
166         MonoMethodVar *vars = cfg->vars;
167         guint32 abs_pos = (bb->dfn << 16);
168         
169         for (inst_num = 0, ins = bb->code; ins; ins = ins->next, inst_num += 2) {
170                 const char *spec = INS_INFO (ins->opcode);
171
172 #ifdef DEBUG_LIVENESS
173                         printf ("\t"); mono_print_ins (ins);
174 #endif
175
176                 if (ins->opcode == OP_NOP)
177                         continue;
178
179                 if (ins->opcode == OP_LDADDR) {
180                         MonoInst *var = ins->inst_p0;
181                         int idx = var->inst_c0;
182                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
183
184 #ifdef DEBUG_LIVENESS
185                         printf ("\tGEN: R%d(%d)\n", var->dreg, idx);
186 #endif
187                         update_live_range (&vars [idx], abs_pos + inst_num); 
188                         if (!mono_bitset_test_fast (bb->kill_set, idx))
189                                 mono_bitset_set_fast (bb->gen_set, idx);
190                         vi->spill_costs += SPILL_COST_INCREMENT;
191                 }                               
192
193                 /* SREGs must come first, so MOVE r <- r is handled correctly */
194
195                 /* SREG1 */
196                 sreg = ins->sreg1;
197                 if ((spec [MONO_INST_SRC1] != ' ') && get_vreg_to_inst (cfg, sreg)) {
198                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
199                         int idx = var->inst_c0;
200                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
201
202 #ifdef DEBUG_LIVENESS
203                         printf ("\tGEN: R%d(%d)\n", sreg, idx);
204 #endif
205                         update_live_range (&vars [idx], abs_pos + inst_num); 
206                         if (!mono_bitset_test_fast (bb->kill_set, idx))
207                                 mono_bitset_set_fast (bb->gen_set, idx);
208                         vi->spill_costs += SPILL_COST_INCREMENT;
209                 }
210
211                 /* SREG2 */
212                 sreg = ins->sreg2;
213                 if ((spec [MONO_INST_SRC2] != ' ') && get_vreg_to_inst (cfg, sreg)) {
214                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
215                         int idx = var->inst_c0;
216                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
217
218 #ifdef DEBUG_LIVENESS
219                         printf ("\tGEN: R%d(%d)\n", sreg, idx);
220 #endif
221                         update_live_range (&vars [idx], abs_pos + inst_num); 
222                         if (!mono_bitset_test_fast (bb->kill_set, idx))
223                                 mono_bitset_set_fast (bb->gen_set, idx);
224                         vi->spill_costs += SPILL_COST_INCREMENT;
225                 }
226
227                 /* DREG */
228                 if ((spec [MONO_INST_DEST] != ' ') && get_vreg_to_inst (cfg, ins->dreg)) {
229                         MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
230                         int idx = var->inst_c0;
231                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
232
233                         if (MONO_IS_STORE_MEMBASE (ins)) {
234                                 update_live_range (&vars [idx], abs_pos + inst_num); 
235                                 if (!mono_bitset_test_fast (bb->kill_set, idx))
236                                         mono_bitset_set_fast (bb->gen_set, idx);
237                                 vi->spill_costs += SPILL_COST_INCREMENT;
238                         } else {
239 #ifdef DEBUG_LIVENESS
240                                 printf ("\tKILL: R%d(%d)\n", ins->dreg, idx);
241 #endif
242                                 update_live_range (&vars [idx], abs_pos + inst_num + 1); 
243                                 mono_bitset_set_fast (bb->kill_set, idx);
244                                 vi->spill_costs += SPILL_COST_INCREMENT;
245                         }
246                 }
247         }
248 }
249
250 /* generic liveness analysis code. CFG specific parts are 
251  * in update_gen_kill_set()
252  */
253 void
254 mono_analyze_liveness (MonoCompile *cfg)
255 {
256         MonoBitSet *old_live_out_set;
257         int i, j, max_vars = cfg->num_varinfo;
258         int out_iter;
259         gboolean *in_worklist;
260         MonoBasicBlock **worklist;
261         guint32 l_end;
262         int bitsize;
263
264 #ifdef DEBUG_LIVENESS
265         printf ("LIVENESS %s\n", mono_method_full_name (cfg->method, TRUE));
266 #endif
267
268         g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS));
269
270         cfg->comp_done |= MONO_COMP_LIVENESS;
271         
272         if (max_vars == 0)
273                 return;
274
275         bitsize = mono_bitset_alloc_size (max_vars, 0);
276
277         for (i = 0; i < max_vars; i ++) {
278                 MONO_VARINFO (cfg, i)->range.first_use.abs_pos = ~ 0;
279                 MONO_VARINFO (cfg, i)->range.last_use .abs_pos =   0;
280                 MONO_VARINFO (cfg, i)->spill_costs = 0;
281         }
282
283         for (i = 0; i < cfg->num_bblocks; ++i) {
284                 MonoBasicBlock *bb = cfg->bblocks [i];
285
286                 bb->gen_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
287                 bb->kill_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
288
289                 analyze_liveness_bb (cfg, bb);
290
291 #ifdef DEBUG_LIVENESS
292                 printf ("BLOCK BB%d (", bb->block_num);
293                 for (j = 0; j < bb->out_count; j++) 
294                         printf ("BB%d, ", bb->out_bb [j]->block_num);
295                 
296                 printf (")\n");
297                 printf ("GEN  BB%d: ", bb->block_num); mono_bitset_print (bb->gen_set);
298                 printf ("KILL BB%d: ", bb->block_num); mono_bitset_print (bb->kill_set);
299 #endif
300         }
301
302         old_live_out_set = mono_bitset_new (max_vars, 0);
303         in_worklist = g_new0 (gboolean, cfg->num_bblocks + 1);
304
305         worklist = g_new (MonoBasicBlock *, cfg->num_bblocks + 1);
306         l_end = 0;
307
308         /*
309          * This is a backward dataflow analysis problem, so we process blocks in
310          * decreasing dfn order, this speeds up the iteration.
311          */
312         for (i = 0; i < cfg->num_bblocks; i ++) {
313                 MonoBasicBlock *bb = cfg->bblocks [i];
314
315                 worklist [l_end ++] = bb;
316                 in_worklist [bb->dfn] = TRUE;
317
318                 /* Initialized later */
319                 bb->live_in_set = NULL;
320                 bb->live_out_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
321         }
322
323         out_iter = 0;
324
325         while (l_end != 0) {
326                 MonoBasicBlock *bb = worklist [--l_end];
327                 MonoBasicBlock *out_bb;
328                 gboolean changed;
329
330                 in_worklist [bb->dfn] = FALSE;
331
332 #ifdef DEBUG_LIVENESS
333                 printf ("P: %d(%d): IN: ", bb->block_num, bb->dfn);
334                 for (j = 0; j < bb->in_count; ++j) 
335                         printf ("BB%d ", bb->in_bb [j]->block_num);
336                 printf ("OUT:");
337                 for (j = 0; j < bb->out_count; ++j) 
338                         printf ("BB%d ", bb->out_bb [j]->block_num);
339                 printf ("\n");
340 #endif
341
342
343                 if (bb->out_count == 0)
344                         continue;
345
346                 out_iter ++;
347
348                 if (!bb->live_in_set) {
349                         /* First pass over this bblock */
350                         changed = TRUE;
351                 }
352                 else {
353                         changed = FALSE;
354                         mono_bitset_copyto_fast (bb->live_out_set, old_live_out_set);
355                 }
356  
357                 for (j = 0; j < bb->out_count; j++) {
358                         out_bb = bb->out_bb [j];
359
360                         if (!out_bb->live_in_set) {
361                                 out_bb->live_in_set = mono_bitset_mp_new_noinit (cfg->mempool, bitsize, max_vars);
362
363                                 mono_bitset_copyto_fast (out_bb->live_out_set, out_bb->live_in_set);
364                                 mono_bitset_sub_fast (out_bb->live_in_set, out_bb->kill_set);
365                                 mono_bitset_union_fast (out_bb->live_in_set, out_bb->gen_set);
366                         }
367
368                         mono_bitset_union_fast (bb->live_out_set, out_bb->live_in_set);
369                 }
370                                 
371                 if (changed || !mono_bitset_equal (old_live_out_set, bb->live_out_set)) {
372                         if (!bb->live_in_set)
373                                 bb->live_in_set = mono_bitset_mp_new_noinit (cfg->mempool, bitsize, max_vars);
374                         mono_bitset_copyto_fast (bb->live_out_set, bb->live_in_set);
375                         mono_bitset_sub_fast (bb->live_in_set, bb->kill_set);
376                         mono_bitset_union_fast (bb->live_in_set, bb->gen_set);
377
378                         for (j = 0; j < bb->in_count; j++) {
379                                 MonoBasicBlock *in_bb = bb->in_bb [j];
380                                 /* 
381                                  * Some basic blocks do not seem to be in the 
382                                  * cfg->bblocks array...
383                                  */
384                                 if (in_bb->gen_set && !in_worklist [in_bb->dfn]) {
385 #ifdef DEBUG_LIVENESS
386                                         printf ("\tADD: %d\n", in_bb->block_num);
387 #endif
388                                         /*
389                                          * Put the block at the top of the stack, so it
390                                          * will be processed right away.
391                                          */
392                                         worklist [l_end ++] = in_bb;
393                                         in_worklist [in_bb->dfn] = TRUE;
394                                 }
395                         }
396                 }
397         }
398
399 #ifdef DEBUG_LIVENESS
400                 printf ("IT: %d %d.\n", cfg->num_bblocks, out_iter);
401 #endif
402
403         mono_bitset_free (old_live_out_set);
404
405         g_free (worklist);
406         g_free (in_worklist);
407
408         /* Compute live_in_set for bblocks skipped earlier */
409         for (i = 0; i < cfg->num_bblocks; ++i) {
410                 MonoBasicBlock *bb = cfg->bblocks [i];
411
412                 if (!bb->live_in_set) {
413                         bb->live_in_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
414
415                         mono_bitset_copyto_fast (bb->live_out_set, bb->live_in_set);
416                         mono_bitset_sub_fast (bb->live_in_set, bb->kill_set);
417                         mono_bitset_union_fast (bb->live_in_set, bb->gen_set);
418                 }
419         }
420
421         for (i = 0; i < cfg->num_bblocks; ++i) {
422                 MonoBasicBlock *bb = cfg->bblocks [i];
423                 guint32 rem, max;
424                 guint32 abs_pos = (bb->dfn << 16);
425                 MonoMethodVar *vars = cfg->vars;
426
427                 if (!bb->live_out_set)
428                         continue;
429
430                 rem = max_vars % BITS_PER_CHUNK;
431                 max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK);
432                 for (j = 0; j < max; ++j) {
433                         gsize bits_in;
434                         gsize bits_out;
435                         int k;
436
437                         bits_in = mono_bitset_get_fast (bb->live_in_set, j);
438                         bits_out = mono_bitset_get_fast (bb->live_out_set, j);
439
440                         k = (j * BITS_PER_CHUNK);
441                         while ((bits_in || bits_out)) {
442                                 if (bits_in & 1)
443                                         update_live_range (&vars [k], abs_pos + 0);
444                                 if (bits_out & 1)
445                                         update_live_range (&vars [k], abs_pos + 0xffff);
446                                 bits_in >>= 1;
447                                 bits_out >>= 1;
448                                 k ++;
449                         }
450                 }
451         }
452
453         /*
454          * Arguments need to have their live ranges extended to the beginning of
455          * the method to account for the arg reg/memory -> global register copies
456          * in the prolog (bug #74992).
457          */
458
459         for (i = 0; i < max_vars; i ++) {
460                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
461                 if (cfg->varinfo [vi->idx]->opcode == OP_ARG) {
462                         if (vi->range.last_use.abs_pos == 0 && !(cfg->varinfo [vi->idx]->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
463                                 cfg->varinfo [vi->idx]->flags |= MONO_INST_IS_DEAD;
464                         vi->range.first_use.abs_pos = 0;
465                 }
466         }
467
468 #ifdef DEBUG_LIVENESS
469         for (i = cfg->num_bblocks - 1; i >= 0; i--) {
470                 MonoBasicBlock *bb = cfg->bblocks [i];
471                 
472                 printf ("LIVE IN  BB%d: ", bb->block_num); 
473                 mono_bitset_print (bb->live_in_set); 
474                 printf ("LIVE OUT BB%d: ", bb->block_num); 
475                 mono_bitset_print (bb->live_out_set); 
476         }
477 #endif
478
479         if (!cfg->disable_initlocals_opt)
480                 optimize_initlocals (cfg);
481
482 #ifdef ENABLE_LIVENESS2
483         /* This improves code size by about 5% but slows down compilation too much */
484         if (cfg->compile_aot)
485                 mono_analyze_liveness2 (cfg);
486 #endif
487 }
488
489 /**
490  * optimize_initlocals:
491  *
492  * Try to optimize away some of the redundant initialization code inserted because of
493  * 'locals init' using the liveness information.
494  */
495 static void
496 optimize_initlocals (MonoCompile *cfg)
497 {
498         MonoBitSet *used;
499         MonoInst *ins;
500         MonoBasicBlock *initlocals_bb;
501
502         used = mono_bitset_new (cfg->next_vreg + 1, 0);
503
504         mono_bitset_clear_all (used);
505         initlocals_bb = cfg->bb_entry->next_bb;
506         for (ins = initlocals_bb->code; ins; ins = ins->next) {
507                 const char *spec = INS_INFO (ins->opcode);
508
509                 if (spec [MONO_INST_SRC1] != ' ')
510                         mono_bitset_set_fast (used, ins->sreg1);
511                 if (spec [MONO_INST_SRC2] != ' ')
512                         mono_bitset_set_fast (used, ins->sreg2);
513                 if (MONO_IS_STORE_MEMBASE (ins))
514                         mono_bitset_set_fast (used, ins->dreg);
515         }
516
517         for (ins = initlocals_bb->code; ins; ins = ins->next) {
518                 const char *spec = INS_INFO (ins->opcode);
519
520                 /* Look for statements whose dest is not used in this bblock and not live on exit. */
521                 if ((spec [MONO_INST_DEST] != ' ') && !MONO_IS_STORE_MEMBASE (ins)) {
522                         MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
523
524                         if (var && !mono_bitset_test_fast (used, ins->dreg) && !mono_bitset_test_fast (initlocals_bb->live_out_set, var->inst_c0) && (var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
525                                 //printf ("DEAD: "); mono_print_ins (ins);
526                                 if ((ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || (ins->opcode == OP_R8CONST)) {
527                                         NULLIFY_INS (ins);
528                                         MONO_VARINFO (cfg, var->inst_c0)->spill_costs -= 1;
529                                         /* 
530                                          * We should shorten the liveness interval of these vars as well, but
531                                          * don't have enough info to do that.
532                                          */
533                                 }
534                         }
535                 }
536         }
537
538         g_free (used);
539 }
540
541 void
542 mono_linterval_add_range (MonoCompile *cfg, MonoLiveInterval *interval, int from, int to)
543 {
544         MonoLiveRange2 *prev_range, *next_range, *new_range;
545
546         g_assert (to >= from);
547
548         /* Optimize for extending the first interval backwards */
549         if (G_LIKELY (interval->range && (interval->range->from > from) && (interval->range->from == to))) {
550                 interval->range->from = from;
551                 return;
552         }
553
554         /* Find a place in the list for the new range */
555         prev_range = NULL;
556         next_range = interval->range;
557         while ((next_range != NULL) && (next_range->from <= from)) {
558                 prev_range = next_range;
559                 next_range = next_range->next;
560         }
561
562         if (prev_range && prev_range->to == from) {
563                 /* Merge with previous */
564                 prev_range->to = to;
565         } else if (next_range && next_range->from == to) {
566                 /* Merge with previous */
567                 next_range->from = from;
568         } else {
569                 /* Insert it */
570                 new_range = mono_mempool_alloc (cfg->mempool, sizeof (MonoLiveRange2));
571                 new_range->from = from;
572                 new_range->to = to;
573                 new_range->next = NULL;
574
575                 if (prev_range)
576                         prev_range->next = new_range;
577                 else
578                         interval->range = new_range;
579                 if (next_range)
580                         new_range->next = next_range;
581                 else
582                         interval->last_range = new_range;
583         }
584
585         /* FIXME: Merge intersecting ranges */
586 }
587
588 void
589 mono_linterval_print (MonoLiveInterval *interval)
590 {
591         MonoLiveRange2 *range;
592
593         for (range = interval->range; range != NULL; range = range->next)
594                 printf ("[%x-%x] ", range->from, range->to);
595 }
596
597 void
598 mono_linterval_print_nl (MonoLiveInterval *interval)
599 {
600         mono_linterval_print (interval);
601         printf ("\n");
602 }
603
604 /**
605  * mono_linterval_convers:
606  *
607  *   Return whenever INTERVAL covers the position POS.
608  */
609 gboolean
610 mono_linterval_covers (MonoLiveInterval *interval, int pos)
611 {
612         MonoLiveRange2 *range;
613
614         for (range = interval->range; range != NULL; range = range->next) {
615                 if (pos >= range->from && pos <= range->to)
616                         return TRUE;
617                 if (range->from > pos)
618                         return FALSE;
619         }
620
621         return FALSE;
622 }
623
624 /**
625  * mono_linterval_get_intersect_pos:
626  *
627  *   Determine whenever I1 and I2 intersect, and if they do, return the first
628  * point of intersection. Otherwise, return -1.
629  */
630 gint32
631 mono_linterval_get_intersect_pos (MonoLiveInterval *i1, MonoLiveInterval *i2)
632 {
633         MonoLiveRange2 *r1, *r2;
634
635         /* FIXME: Optimize this */
636         for (r1 = i1->range; r1 != NULL; r1 = r1->next) {
637                 for (r2 = i2->range; r2 != NULL; r2 = r2->next) {
638                         if (r2->to > r1->from && r2->from < r1->to) {
639                                 if (r2->from <= r1->from)
640                                         return r1->from;
641                                 else
642                                         return r2->from;
643                         }
644                 }
645         }
646
647         return -1;
648 }
649  
650 /**
651  * mono_linterval_split
652  *
653  *   Split L at POS and store the newly created intervals into L1 and L2. POS becomes
654  * part of L2.
655  */
656 void
657 mono_linterval_split (MonoCompile *cfg, MonoLiveInterval *interval, MonoLiveInterval **i1, MonoLiveInterval **i2, int pos)
658 {
659         MonoLiveRange2 *r;
660
661         g_assert (pos > interval->range->from && pos <= interval->last_range->to);
662
663         *i1 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
664         *i2 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
665
666         for (r = interval->range; r; r = r->next) {
667                 if (pos > r->to) {
668                         /* Add it to the first child */
669                         mono_linterval_add_range (cfg, *i1, r->from, r->to);
670                 } else if (pos > r->from && pos <= r->to) {
671                         /* Split at pos */
672                         mono_linterval_add_range (cfg, *i1, r->from, pos - 1);
673                         mono_linterval_add_range (cfg, *i2, pos, r->to);
674                 } else {
675                         /* Add it to the second child */
676                         mono_linterval_add_range (cfg, *i2, r->from, r->to);
677                 }
678         }
679 }
680
681 #ifdef ENABLE_LIVENESS2
682
683 #if 0
684 #define LIVENESS_DEBUG(a) do { a; } while (0)
685 #else
686 #define LIVENESS_DEBUG(a)
687 #endif
688
689 static inline void
690 update_liveness2 (MonoCompile *cfg, MonoInst *ins, gboolean set_volatile, int inst_num, gint32 *last_use)
691 {
692         const char *spec = INS_INFO (ins->opcode);
693         int sreg;
694
695         LIVENESS_DEBUG (printf ("\t%x: ", inst_num); mono_print_ins (ins));
696
697         if (ins->opcode == OP_NOP)
698                 return;
699
700         /* DREG */
701         if ((spec [MONO_INST_DEST] != ' ') && get_vreg_to_inst (cfg, ins->dreg)) {
702                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
703                 int idx = var->inst_c0;
704                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
705
706                 if (MONO_IS_STORE_MEMBASE (ins)) {
707                         if (last_use [idx] == 0) {
708                                 LIVENESS_DEBUG (printf ("\tlast use of R%d set to %x\n", ins->dreg, inst_num));
709                                 last_use [idx] = inst_num;
710                         }
711                 } else {
712                         if (last_use [idx] > 0) {
713                                 LIVENESS_DEBUG (printf ("\tadd range to R%d: [%x, %x)\n", ins->dreg, inst_num, last_use [idx]));
714                                 mono_linterval_add_range (cfg, vi->interval, inst_num, last_use [idx]);
715                                 last_use [idx] = 0;
716                         }
717                         else {
718                                 /* Try dead code elimination */
719                                 if ((var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && ((ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || (ins->opcode == OP_R8CONST)) && !(var->flags & MONO_INST_VOLATILE)) {
720                                         LIVENESS_DEBUG (printf ("\tdead def of R%d, eliminated\n", ins->dreg));
721                                         ins->opcode = OP_NOP;
722                                         ins->dreg = ins->sreg1 = ins->sreg2 = -1;
723                                         return;
724                                 }
725
726                                 LIVENESS_DEBUG (printf ("\tdead def of R%d, add range to R%d: [%x, %x]\n", ins->dreg, ins->dreg, inst_num, inst_num + 1));
727                                 mono_linterval_add_range (cfg, vi->interval, inst_num, inst_num + 1);
728                         }
729                 }
730         }
731
732         /* SREG1 */
733         sreg = ins->sreg1;
734         if ((spec [MONO_INST_SRC1] != ' ') && get_vreg_to_inst (cfg, sreg)) {
735                 MonoInst *var = get_vreg_to_inst (cfg, sreg);
736                 int idx = var->inst_c0;
737
738                 if (last_use [idx] == 0) {
739                         LIVENESS_DEBUG (printf ("\tlast use of R%d set to %x\n", sreg, inst_num));
740                         last_use [idx] = inst_num;
741                 }
742         }
743
744         /* SREG2 */
745         sreg = ins->sreg2;
746         if ((spec [MONO_INST_SRC2] != ' ') && get_vreg_to_inst (cfg, sreg)) {
747                 MonoInst *var = get_vreg_to_inst (cfg, sreg);
748                 int idx = var->inst_c0;
749
750                 if (last_use [idx] == 0) {
751                         LIVENESS_DEBUG (printf ("\tlast use of R%d set to %x\n", sreg, inst_num));
752                         last_use [idx] = inst_num;
753                 }
754         }
755 }
756
757 static void
758 mono_analyze_liveness2 (MonoCompile *cfg)
759 {
760         int bnum, idx, i, j, nins, rem, max, max_vars, block_from, block_to, pos, reverse_len;
761         gint32 *last_use;
762         static guint32 disabled = -1;
763         MonoInst **reverse;
764
765         if (disabled == -1)
766                 disabled = getenv ("DISABLED") != NULL;
767
768         if (disabled)
769                 return;
770
771         LIVENESS_DEBUG (printf ("LIVENESS 2 %s\n", mono_method_full_name (cfg->method, TRUE)));
772
773         /*
774         if (strstr (cfg->method->name, "test_") != cfg->method->name)
775                 return;
776         */
777
778         max_vars = cfg->num_varinfo;
779         last_use = g_new0 (gint32, max_vars);
780
781         reverse_len = 1024;
782         reverse = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * reverse_len);
783
784         for (idx = 0; idx < max_vars; ++idx) {
785                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
786
787                 vi->interval = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
788         }
789
790         /*
791          * Process bblocks in reverse order, so the addition of new live ranges
792          * to the intervals is faster.
793          */
794         for (bnum = cfg->num_bblocks - 1; bnum >= 0; --bnum) {
795                 MonoBasicBlock *bb = cfg->bblocks [bnum];
796                 MonoInst *ins;
797
798                 block_from = (bb->dfn << 16) + 1; /* so pos > 0 */
799                 if (bnum < cfg->num_bblocks - 1)
800                         /* Beginning of the next bblock */
801                         block_to = (cfg->bblocks [bnum + 1]->dfn << 16) + 1;
802                 else
803                         block_to = (bb->dfn << 16) + 0xffff;
804
805                 LIVENESS_DEBUG (printf ("LIVENESS BLOCK BB%d:\n", bb->block_num));
806
807                 memset (last_use, 0, max_vars * sizeof (gint32));
808                 
809                 /* For variables in bb->live_out, set last_use to block_to */
810
811                 rem = max_vars % BITS_PER_CHUNK;
812                 max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK);
813                 for (j = 0; j < max; ++j) {
814                         gsize bits_out;
815                         int k;
816
817                         bits_out = mono_bitset_get_fast (bb->live_out_set, j);
818                         k = (j * BITS_PER_CHUNK);       
819                         while (bits_out) {
820                                 if (bits_out & 1) {
821                                         LIVENESS_DEBUG (printf ("Var R%d live at exit, set last_use to %x\n", cfg->varinfo [k]->dreg, block_to));
822                                         last_use [k] = block_to;
823                                 }
824                                 bits_out >>= 1;
825                                 k ++;
826                         }
827                 }
828
829                 if (cfg->ret)
830                         last_use [cfg->ret->inst_c0] = block_to;
831
832                 for (nins = 0, pos = block_from, ins = bb->code; ins; ins = ins->next, ++nins, ++pos) {
833                         if (nins >= reverse_len) {
834                                 int new_reverse_len = reverse_len * 2;
835                                 MonoInst **new_reverse = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * new_reverse_len);
836                                 memcpy (new_reverse, reverse, sizeof (MonoInst*) * reverse_len);
837                                 reverse = new_reverse;
838                                 reverse_len = new_reverse_len;
839                         }
840
841                         reverse [nins] = ins;
842                 }
843
844                 /* Process instructions backwards */
845                 for (i = nins - 1; i >= 0; --i) {
846                         MonoInst *ins = (MonoInst*)reverse [i];
847
848                         update_liveness2 (cfg, ins, FALSE, pos, last_use);
849
850                         pos --;
851                 }
852
853                 for (idx = 0; idx < max_vars; ++idx) {
854                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
855
856                         if (last_use [idx] != 0) {
857                                 /* Live at exit, not written -> live on enter */
858                                 LIVENESS_DEBUG (printf ("Var R%d live at enter, add range to R%d: [%x, %x)\n", cfg->varinfo [idx]->dreg, cfg->varinfo [idx]->dreg, block_from, last_use [idx]));
859                                 mono_linterval_add_range (cfg, vi->interval, block_from, last_use [idx]);
860                         }
861                 }
862         }
863
864         /*
865          * Arguments need to have their live ranges extended to the beginning of
866          * the method to account for the arg reg/memory -> global register copies
867          * in the prolog (bug #74992).
868          */
869         for (i = 0; i < max_vars; i ++) {
870                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
871                 if (cfg->varinfo [vi->idx]->opcode == OP_ARG)
872                         mono_linterval_add_range (cfg, vi->interval, 0, 1);
873         }
874
875 #if 0
876         for (idx = 0; idx < max_vars; ++idx) {
877                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
878                 
879                 LIVENESS_DEBUG (printf ("LIVENESS R%d: ", cfg->varinfo [idx]->dreg));
880                 LIVENESS_DEBUG (mono_linterval_print (vi->interval));
881                 LIVENESS_DEBUG (printf ("\n"));
882         }
883 #endif
884
885         g_free (last_use);
886 }
887
888 #endif