Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[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  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9  */
10
11 #include <config.h>
12
13 #ifndef DISABLE_JIT
14
15 #include "mini.h"
16
17 #define SPILL_COST_INCREMENT (1 << (bb->nesting << 1))
18
19 #define DEBUG_LIVENESS
20
21 #define BITS_PER_CHUNK MONO_BITSET_BITS_PER_CHUNK
22
23 /* 
24  * The liveness2 pass can't handle long vars on 32 bit platforms because the component
25  * vars have the same 'idx'.
26  */
27 #if SIZEOF_REGISTER == 8
28 #define ENABLE_LIVENESS2
29 #endif
30
31 #ifdef ENABLE_LIVENESS2
32 static void mono_analyze_liveness2 (MonoCompile *cfg);
33 #endif
34
35 static void
36 optimize_initlocals (MonoCompile *cfg);
37
38 /* mono_bitset_mp_new:
39  * 
40  * allocates a MonoBitSet inside a memory pool
41  */
42 static inline MonoBitSet* 
43 mono_bitset_mp_new (MonoMemPool *mp, guint32 size, guint32 max_size)
44 {
45         guint8 *mem = mono_mempool_alloc0 (mp, size);
46         return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
47 }
48
49 static inline MonoBitSet* 
50 mono_bitset_mp_new_noinit (MonoMemPool *mp, guint32 size, guint32 max_size)
51 {
52         guint8 *mem = mono_mempool_alloc (mp, size);
53         return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
54 }
55
56 G_GNUC_UNUSED static void
57 mono_bitset_print (MonoBitSet *set)
58 {
59         int i;
60         gboolean first = TRUE;
61
62         printf ("{");
63         for (i = 0; i < mono_bitset_size (set); i++) {
64
65                 if (mono_bitset_test (set, i)) {
66                         if (!first)
67                                 printf (", ");
68                         printf ("%d", i);
69                         first = FALSE;
70                 }
71         }
72         printf ("}\n");
73 }
74
75 static void
76 visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, GSList **visited)
77 {
78         int i;
79         MonoInst *ins;
80
81         if (g_slist_find (*visited, bb))
82                 return;
83
84         for (ins = bb->code; ins; ins = ins->next) {
85                 const char *spec = INS_INFO (ins->opcode);
86                 int regtype, srcindex, sreg, num_sregs;
87                 int sregs [MONO_MAX_SRC_REGS];
88
89                 if (ins->opcode == OP_NOP)
90                         continue;
91
92                 /* DREG */
93                 regtype = spec [MONO_INST_DEST];
94                 g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
95                                 
96                 if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
97                         MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
98                         int idx = var->inst_c0;
99                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
100
101                         cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
102                         if (SIZEOF_REGISTER == 4 && (var->type == STACK_I8 || (var->type == STACK_R8 && COMPILE_SOFT_FLOAT (cfg)))) {
103                                 /* Make the component vregs volatile as well (#612206) */
104                                 get_vreg_to_inst (cfg, var->dreg + 1)->flags |= MONO_INST_VOLATILE;
105                                 get_vreg_to_inst (cfg, var->dreg + 2)->flags |= MONO_INST_VOLATILE;
106                         }
107                 }
108                         
109                 /* SREGS */
110                 num_sregs = mono_inst_get_src_registers (ins, sregs);
111                 for (srcindex = 0; srcindex < num_sregs; ++srcindex) {
112                         sreg = sregs [srcindex];
113
114                         g_assert (sreg != -1);
115                         if (get_vreg_to_inst (cfg, sreg)) {
116                                 MonoInst *var = get_vreg_to_inst (cfg, sreg);
117                                 int idx = var->inst_c0;
118                                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
119
120                                 cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
121                                 if (SIZEOF_REGISTER == 4 && (var->type == STACK_I8 || (var->type == STACK_R8 && COMPILE_SOFT_FLOAT (cfg)))) {
122                                         /* Make the component vregs volatile as well (#612206) */
123                                         get_vreg_to_inst (cfg, var->dreg + 1)->flags |= MONO_INST_VOLATILE;
124                                         get_vreg_to_inst (cfg, var->dreg + 2)->flags |= MONO_INST_VOLATILE;
125                                 }
126                         }
127                 }
128         }
129
130         *visited = g_slist_append (*visited, bb);
131
132         /* 
133          * Need to visit all bblocks reachable from this one since they can be
134          * reached during exception handling.
135          */
136         for (i = 0; i < bb->out_count; ++i) {
137                 visit_bb (cfg, bb->out_bb [i], visited);
138         }
139 }
140
141 void
142 mono_liveness_handle_exception_clauses (MonoCompile *cfg)
143 {
144         MonoBasicBlock *bb;
145         GSList *visited = NULL;
146         MonoMethodHeader *header = cfg->header;
147         MonoExceptionClause *clause, *clause2;
148         int i, j;
149         gboolean *outer_try;
150
151         /* 
152          * Determine which clauses are outer try clauses, i.e. they are not contained in any
153          * other non-try clause.
154          */
155         outer_try = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * header->num_clauses);
156         for (i = 0; i < header->num_clauses; ++i)
157                 outer_try [i] = TRUE;
158         /* Iterate over the clauses backward, so outer clauses come first */
159         /* This avoids doing an O(2) search, since we can determine when inner clauses end */
160         for (i = header->num_clauses - 1; i >= 0; --i) {
161                 clause = &header->clauses [i];
162
163                 if (clause->flags != 0) {
164                         outer_try [i] = TRUE;
165                         /* Iterate over inner clauses */
166                         for (j = i - 1; j >= 0; --j) {
167                                 clause2 = &header->clauses [j];
168
169                                 if (clause2->flags == 0 && MONO_OFFSET_IN_HANDLER (clause, clause2->try_offset)) {
170                                         outer_try [j] = FALSE;
171                                         break;
172                                 }
173                                 if (clause2->try_offset < clause->try_offset)
174                                         /* End of inner clauses */
175                                         break;
176                         }
177                 }
178         }
179
180         /*
181          * Variables in exception handler register cannot be allocated to registers
182          * so make them volatile. See bug #42136. This will not be neccessary when
183          * the back ends could guarantee that the variables will be in the
184          * correct registers when a handler is called.
185          * This includes try blocks too, since a variable in a try block might be
186          * accessed after an exception handler has been run.
187          */
188         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
189
190                 if (bb->region == -1)
191                         continue;
192
193                 if (MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY) && outer_try [MONO_REGION_CLAUSE_INDEX (bb->region)])
194                         continue;
195
196                 if (cfg->verbose_level > 2)
197                         printf ("pessimize variables in bb %d.\n", bb->block_num);
198
199                 visit_bb (cfg, bb, &visited);
200         }
201         g_slist_free (visited);
202 }
203
204 static inline void
205 update_live_range (MonoMethodVar *var, int abs_pos)
206 {
207         if (var->range.first_use.abs_pos > abs_pos)
208                 var->range.first_use.abs_pos = abs_pos;
209
210         if (var->range.last_use.abs_pos < abs_pos)
211                 var->range.last_use.abs_pos = abs_pos;
212 }
213
214 static void
215 analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb)
216 {
217         MonoInst *ins;
218         int sreg, inst_num;
219         MonoMethodVar *vars = cfg->vars;
220         guint32 abs_pos = (bb->dfn << 16);
221         
222         /* Start inst_num from > 0, so last_use.abs_pos is only 0 for dead variables */
223         for (inst_num = 2, ins = bb->code; ins; ins = ins->next, inst_num += 2) {
224                 const char *spec = INS_INFO (ins->opcode);
225                 int num_sregs, i;
226                 int sregs [MONO_MAX_SRC_REGS];
227
228 #ifdef DEBUG_LIVENESS
229                 if (cfg->verbose_level > 1) {
230                         printf ("\t");
231                         mono_print_ins (ins);
232                 }
233 #endif
234
235                 if (ins->opcode == OP_NOP)
236                         continue;
237
238                 if (ins->opcode == OP_LDADDR) {
239                         MonoInst *var = ins->inst_p0;
240                         int idx = var->inst_c0;
241                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
242
243 #ifdef DEBUG_LIVENESS
244                         if (cfg->verbose_level > 1)
245                                 printf ("\tGEN: R%d(%d)\n", var->dreg, idx);
246 #endif
247                         update_live_range (&vars [idx], abs_pos + inst_num); 
248                         if (!mono_bitset_test_fast (bb->kill_set, idx))
249                                 mono_bitset_set_fast (bb->gen_set, idx);
250                         vi->spill_costs += SPILL_COST_INCREMENT;
251                 }                               
252
253                 /* SREGs must come first, so MOVE r <- r is handled correctly */
254                 num_sregs = mono_inst_get_src_registers (ins, sregs);
255                 for (i = 0; i < num_sregs; ++i) {
256                         sreg = sregs [i];
257                         if ((spec [MONO_INST_SRC1 + i] != ' ') && get_vreg_to_inst (cfg, sreg)) {
258                                 MonoInst *var = get_vreg_to_inst (cfg, sreg);
259                                 int idx = var->inst_c0;
260                                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
261
262 #ifdef DEBUG_LIVENESS
263                                 if (cfg->verbose_level > 1)
264                                         printf ("\tGEN: R%d(%d)\n", sreg, idx);
265 #endif
266                                 update_live_range (&vars [idx], abs_pos + inst_num); 
267                                 if (!mono_bitset_test_fast (bb->kill_set, idx))
268                                         mono_bitset_set_fast (bb->gen_set, idx);
269                                 vi->spill_costs += SPILL_COST_INCREMENT;
270                         }
271                 }
272
273                 /* DREG */
274                 if ((spec [MONO_INST_DEST] != ' ') && get_vreg_to_inst (cfg, ins->dreg)) {
275                         MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
276                         int idx = var->inst_c0;
277                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
278
279                         if (MONO_IS_STORE_MEMBASE (ins)) {
280                                 update_live_range (&vars [idx], abs_pos + inst_num); 
281                                 if (!mono_bitset_test_fast (bb->kill_set, idx))
282                                         mono_bitset_set_fast (bb->gen_set, idx);
283                                 vi->spill_costs += SPILL_COST_INCREMENT;
284                         } else {
285 #ifdef DEBUG_LIVENESS
286                                 if (cfg->verbose_level > 1)
287                                         printf ("\tKILL: R%d(%d)\n", ins->dreg, idx);
288 #endif
289                                 update_live_range (&vars [idx], abs_pos + inst_num + 1); 
290                                 mono_bitset_set_fast (bb->kill_set, idx);
291                                 vi->spill_costs += SPILL_COST_INCREMENT;
292                         }
293                 }
294         }
295 }
296
297 /* generic liveness analysis code. CFG specific parts are 
298  * in update_gen_kill_set()
299  */
300 void
301 mono_analyze_liveness (MonoCompile *cfg)
302 {
303         MonoBitSet *old_live_out_set;
304         int i, j, max_vars = cfg->num_varinfo;
305         int out_iter;
306         gboolean *in_worklist;
307         MonoBasicBlock **worklist;
308         guint32 l_end;
309         int bitsize;
310
311 #ifdef DEBUG_LIVENESS
312         if (cfg->verbose_level > 1)
313                 printf ("\nLIVENESS:\n");
314 #endif
315
316         g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS));
317
318         cfg->comp_done |= MONO_COMP_LIVENESS;
319         
320         if (max_vars == 0)
321                 return;
322
323         bitsize = mono_bitset_alloc_size (max_vars, 0);
324
325         for (i = 0; i < max_vars; i ++) {
326                 MONO_VARINFO (cfg, i)->range.first_use.abs_pos = ~ 0;
327                 MONO_VARINFO (cfg, i)->range.last_use .abs_pos =   0;
328                 MONO_VARINFO (cfg, i)->spill_costs = 0;
329         }
330
331         for (i = 0; i < cfg->num_bblocks; ++i) {
332                 MonoBasicBlock *bb = cfg->bblocks [i];
333
334                 bb->gen_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
335                 bb->kill_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
336
337 #ifdef DEBUG_LIVENESS
338                 if (cfg->verbose_level > 1) {
339                         printf ("BLOCK BB%d (", bb->block_num);
340                         for (j = 0; j < bb->out_count; j++) 
341                                 printf ("BB%d, ", bb->out_bb [j]->block_num);
342                 
343                         printf ("):\n");
344                 }
345 #endif
346
347                 analyze_liveness_bb (cfg, bb);
348
349 #ifdef DEBUG_LIVENESS
350                 if (cfg->verbose_level > 1) {
351                         printf ("GEN  BB%d: ", bb->block_num); mono_bitset_print (bb->gen_set);
352                         printf ("KILL BB%d: ", bb->block_num); mono_bitset_print (bb->kill_set);
353                 }
354 #endif
355         }
356
357         old_live_out_set = mono_bitset_new (max_vars, 0);
358         in_worklist = g_new0 (gboolean, cfg->num_bblocks + 1);
359
360         worklist = g_new (MonoBasicBlock *, cfg->num_bblocks + 1);
361         l_end = 0;
362
363         /*
364          * This is a backward dataflow analysis problem, so we process blocks in
365          * decreasing dfn order, this speeds up the iteration.
366          */
367         for (i = 0; i < cfg->num_bblocks; i ++) {
368                 MonoBasicBlock *bb = cfg->bblocks [i];
369
370                 worklist [l_end ++] = bb;
371                 in_worklist [bb->dfn] = TRUE;
372
373                 /* Initialized later */
374                 bb->live_in_set = NULL;
375                 bb->live_out_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
376         }
377
378         out_iter = 0;
379
380         if (cfg->verbose_level > 1)
381                 printf ("\nITERATION:\n");
382
383         while (l_end != 0) {
384                 MonoBasicBlock *bb = worklist [--l_end];
385                 MonoBasicBlock *out_bb;
386                 gboolean changed;
387
388                 in_worklist [bb->dfn] = FALSE;
389
390 #ifdef DEBUG_LIVENESS
391                 if (cfg->verbose_level > 1) {
392                         printf ("P: BB%d(%d): IN: ", bb->block_num, bb->dfn);
393                         for (j = 0; j < bb->in_count; ++j) 
394                                 printf ("BB%d ", bb->in_bb [j]->block_num);
395                         printf ("OUT:");
396                         for (j = 0; j < bb->out_count; ++j) 
397                                 printf ("BB%d ", bb->out_bb [j]->block_num);
398                         printf ("\n");
399                 }
400 #endif
401
402
403                 if (bb->out_count == 0)
404                         continue;
405
406                 out_iter ++;
407
408                 if (!bb->live_in_set) {
409                         /* First pass over this bblock */
410                         changed = TRUE;
411                 }
412                 else {
413                         changed = FALSE;
414                         mono_bitset_copyto_fast (bb->live_out_set, old_live_out_set);
415                 }
416  
417                 for (j = 0; j < bb->out_count; j++) {
418                         out_bb = bb->out_bb [j];
419
420                         if (!out_bb->live_in_set) {
421                                 out_bb->live_in_set = mono_bitset_mp_new_noinit (cfg->mempool, bitsize, max_vars);
422
423                                 mono_bitset_copyto_fast (out_bb->live_out_set, out_bb->live_in_set);
424                                 mono_bitset_sub_fast (out_bb->live_in_set, out_bb->kill_set);
425                                 mono_bitset_union_fast (out_bb->live_in_set, out_bb->gen_set);
426                         }
427
428                         // FIXME: Do this somewhere else
429                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
430                         } else {
431                                 mono_bitset_union_fast (bb->live_out_set, out_bb->live_in_set);
432                         }
433                 }
434                                 
435                 if (changed || !mono_bitset_equal (old_live_out_set, bb->live_out_set)) {
436                         if (!bb->live_in_set)
437                                 bb->live_in_set = mono_bitset_mp_new_noinit (cfg->mempool, bitsize, max_vars);
438                         mono_bitset_copyto_fast (bb->live_out_set, bb->live_in_set);
439                         mono_bitset_sub_fast (bb->live_in_set, bb->kill_set);
440                         mono_bitset_union_fast (bb->live_in_set, bb->gen_set);
441
442                         for (j = 0; j < bb->in_count; j++) {
443                                 MonoBasicBlock *in_bb = bb->in_bb [j];
444                                 /* 
445                                  * Some basic blocks do not seem to be in the 
446                                  * cfg->bblocks array...
447                                  */
448                                 if (in_bb->gen_set && !in_worklist [in_bb->dfn]) {
449 #ifdef DEBUG_LIVENESS
450                                         if (cfg->verbose_level > 1)
451                                                 printf ("\tADD: %d\n", in_bb->block_num);
452 #endif
453                                         /*
454                                          * Put the block at the top of the stack, so it
455                                          * will be processed right away.
456                                          */
457                                         worklist [l_end ++] = in_bb;
458                                         in_worklist [in_bb->dfn] = TRUE;
459                                 }
460                         }
461                 }
462
463                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
464                         printf ("\tLIVE IN  BB%d: ", bb->block_num); 
465                         mono_bitset_print (bb->live_in_set); 
466                 }                       
467         }
468
469 #ifdef DEBUG_LIVENESS
470         if (cfg->verbose_level > 1)
471                 printf ("IT: %d %d.\n", cfg->num_bblocks, out_iter);
472 #endif
473
474         mono_bitset_free (old_live_out_set);
475
476         g_free (worklist);
477         g_free (in_worklist);
478
479         /* Compute live_in_set for bblocks skipped earlier */
480         for (i = 0; i < cfg->num_bblocks; ++i) {
481                 MonoBasicBlock *bb = cfg->bblocks [i];
482
483                 if (!bb->live_in_set) {
484                         bb->live_in_set = mono_bitset_mp_new (cfg->mempool, bitsize, max_vars);
485
486                         mono_bitset_copyto_fast (bb->live_out_set, bb->live_in_set);
487                         mono_bitset_sub_fast (bb->live_in_set, bb->kill_set);
488                         mono_bitset_union_fast (bb->live_in_set, bb->gen_set);
489                 }
490         }
491
492         for (i = 0; i < cfg->num_bblocks; ++i) {
493                 MonoBasicBlock *bb = cfg->bblocks [i];
494                 guint32 max;
495                 guint32 abs_pos = (bb->dfn << 16);
496                 MonoMethodVar *vars = cfg->vars;
497
498                 if (!bb->live_out_set)
499                         continue;
500
501                 max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK);
502                 for (j = 0; j < max; ++j) {
503                         gsize bits_in;
504                         gsize bits_out;
505                         int k;
506
507                         bits_in = mono_bitset_get_fast (bb->live_in_set, j);
508                         bits_out = mono_bitset_get_fast (bb->live_out_set, j);
509
510                         k = (j * BITS_PER_CHUNK);
511                         while ((bits_in || bits_out)) {
512                                 if (bits_in & 1)
513                                         update_live_range (&vars [k], abs_pos + 0);
514                                 if (bits_out & 1)
515                                         update_live_range (&vars [k], abs_pos + 0xffff);
516                                 bits_in >>= 1;
517                                 bits_out >>= 1;
518                                 k ++;
519                         }
520                 }
521         }
522
523         /*
524          * Arguments need to have their live ranges extended to the beginning of
525          * the method to account for the arg reg/memory -> global register copies
526          * in the prolog (bug #74992).
527          */
528
529         for (i = 0; i < max_vars; i ++) {
530                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
531                 if (cfg->varinfo [vi->idx]->opcode == OP_ARG) {
532                         if (vi->range.last_use.abs_pos == 0 && !(cfg->varinfo [vi->idx]->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
533                                 /* 
534                                  * Can't eliminate the this variable in gshared code, since
535                                  * it is needed during exception handling to identify the
536                                  * method.
537                                  * It is better to check for this here instead of marking the variable
538                                  * VOLATILE, since that would prevent it from being allocated to
539                                  * registers.
540                                  */
541                                  if (!cfg->disable_deadce_vars && !(cfg->generic_sharing_context && mono_method_signature (cfg->method)->hasthis && cfg->varinfo [vi->idx] == cfg->args [0]))
542                                          cfg->varinfo [vi->idx]->flags |= MONO_INST_IS_DEAD;
543                         }
544                         vi->range.first_use.abs_pos = 0;
545                 }
546         }
547
548 #ifdef DEBUG_LIVENESS
549         if (cfg->verbose_level > 1) {
550                 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
551                         MonoBasicBlock *bb = cfg->bblocks [i];
552                 
553                         printf ("LIVE IN  BB%d: ", bb->block_num); 
554                         mono_bitset_print (bb->live_in_set); 
555                         printf ("LIVE OUT BB%d: ", bb->block_num); 
556                         mono_bitset_print (bb->live_out_set); 
557                 }
558
559                 for (i = 0; i < max_vars; i ++) {
560                         MonoMethodVar *vi = MONO_VARINFO (cfg, i);
561
562                         printf ("V%d: [0x%x - 0x%x]\n", i, vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
563                 }
564         }
565 #endif
566
567         if (!cfg->disable_initlocals_opt)
568                 optimize_initlocals (cfg);
569
570 #ifdef ENABLE_LIVENESS2
571         /* This improves code size by about 5% but slows down compilation too much */
572         if (cfg->compile_aot)
573                 mono_analyze_liveness2 (cfg);
574 #endif
575 }
576
577 /**
578  * optimize_initlocals:
579  *
580  * Try to optimize away some of the redundant initialization code inserted because of
581  * 'locals init' using the liveness information.
582  */
583 static void
584 optimize_initlocals (MonoCompile *cfg)
585 {
586         MonoBitSet *used;
587         MonoInst *ins;
588         MonoBasicBlock *initlocals_bb;
589
590         used = mono_bitset_new (cfg->next_vreg + 1, 0);
591
592         mono_bitset_clear_all (used);
593         initlocals_bb = cfg->bb_entry->next_bb;
594         for (ins = initlocals_bb->code; ins; ins = ins->next) {
595                 int num_sregs, i;
596                 int sregs [MONO_MAX_SRC_REGS];
597
598                 num_sregs = mono_inst_get_src_registers (ins, sregs);
599                 for (i = 0; i < num_sregs; ++i)
600                         mono_bitset_set_fast (used, sregs [i]);
601
602                 if (MONO_IS_STORE_MEMBASE (ins))
603                         mono_bitset_set_fast (used, ins->dreg);
604         }
605
606         for (ins = initlocals_bb->code; ins; ins = ins->next) {
607                 const char *spec = INS_INFO (ins->opcode);
608
609                 /* Look for statements whose dest is not used in this bblock and not live on exit. */
610                 if ((spec [MONO_INST_DEST] != ' ') && !MONO_IS_STORE_MEMBASE (ins)) {
611                         MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
612
613                         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))) {
614                                 //printf ("DEAD: "); mono_print_ins (ins);
615                                 if (cfg->disable_initlocals_opt_refs && var->type == STACK_OBJ)
616                                         continue;
617                                 if ((ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || (ins->opcode == OP_R8CONST)) {
618                                         NULLIFY_INS (ins);
619                                         MONO_VARINFO (cfg, var->inst_c0)->spill_costs -= 1;
620                                         /* 
621                                          * We should shorten the liveness interval of these vars as well, but
622                                          * don't have enough info to do that.
623                                          */
624                                 }
625                         }
626                 }
627         }
628
629         g_free (used);
630 }
631
632 void
633 mono_linterval_add_range (MonoCompile *cfg, MonoLiveInterval *interval, int from, int to)
634 {
635         MonoLiveRange2 *prev_range, *next_range, *new_range;
636
637         g_assert (to >= from);
638
639         /* Optimize for extending the first interval backwards */
640         if (G_LIKELY (interval->range && (interval->range->from > from) && (interval->range->from == to))) {
641                 interval->range->from = from;
642                 return;
643         }
644
645         /* Find a place in the list for the new range */
646         prev_range = NULL;
647         next_range = interval->range;
648         while ((next_range != NULL) && (next_range->from <= from)) {
649                 prev_range = next_range;
650                 next_range = next_range->next;
651         }
652
653         if (prev_range && prev_range->to == from) {
654                 /* Merge with previous */
655                 prev_range->to = to;
656         } else if (next_range && next_range->from == to) {
657                 /* Merge with previous */
658                 next_range->from = from;
659         } else {
660                 /* Insert it */
661                 new_range = mono_mempool_alloc (cfg->mempool, sizeof (MonoLiveRange2));
662                 new_range->from = from;
663                 new_range->to = to;
664                 new_range->next = NULL;
665
666                 if (prev_range)
667                         prev_range->next = new_range;
668                 else
669                         interval->range = new_range;
670                 if (next_range)
671                         new_range->next = next_range;
672                 else
673                         interval->last_range = new_range;
674         }
675
676         /* FIXME: Merge intersecting ranges */
677 }
678
679 void
680 mono_linterval_print (MonoLiveInterval *interval)
681 {
682         MonoLiveRange2 *range;
683
684         for (range = interval->range; range != NULL; range = range->next)
685                 printf ("[%x-%x] ", range->from, range->to);
686 }
687
688 void
689 mono_linterval_print_nl (MonoLiveInterval *interval)
690 {
691         mono_linterval_print (interval);
692         printf ("\n");
693 }
694
695 /**
696  * mono_linterval_convers:
697  *
698  *   Return whenever INTERVAL covers the position POS.
699  */
700 gboolean
701 mono_linterval_covers (MonoLiveInterval *interval, int pos)
702 {
703         MonoLiveRange2 *range;
704
705         for (range = interval->range; range != NULL; range = range->next) {
706                 if (pos >= range->from && pos <= range->to)
707                         return TRUE;
708                 if (range->from > pos)
709                         return FALSE;
710         }
711
712         return FALSE;
713 }
714
715 /**
716  * mono_linterval_get_intersect_pos:
717  *
718  *   Determine whenever I1 and I2 intersect, and if they do, return the first
719  * point of intersection. Otherwise, return -1.
720  */
721 gint32
722 mono_linterval_get_intersect_pos (MonoLiveInterval *i1, MonoLiveInterval *i2)
723 {
724         MonoLiveRange2 *r1, *r2;
725
726         /* FIXME: Optimize this */
727         for (r1 = i1->range; r1 != NULL; r1 = r1->next) {
728                 for (r2 = i2->range; r2 != NULL; r2 = r2->next) {
729                         if (r2->to > r1->from && r2->from < r1->to) {
730                                 if (r2->from <= r1->from)
731                                         return r1->from;
732                                 else
733                                         return r2->from;
734                         }
735                 }
736         }
737
738         return -1;
739 }
740  
741 /**
742  * mono_linterval_split
743  *
744  *   Split L at POS and store the newly created intervals into L1 and L2. POS becomes
745  * part of L2.
746  */
747 void
748 mono_linterval_split (MonoCompile *cfg, MonoLiveInterval *interval, MonoLiveInterval **i1, MonoLiveInterval **i2, int pos)
749 {
750         MonoLiveRange2 *r;
751
752         g_assert (pos > interval->range->from && pos <= interval->last_range->to);
753
754         *i1 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
755         *i2 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
756
757         for (r = interval->range; r; r = r->next) {
758                 if (pos > r->to) {
759                         /* Add it to the first child */
760                         mono_linterval_add_range (cfg, *i1, r->from, r->to);
761                 } else if (pos > r->from && pos <= r->to) {
762                         /* Split at pos */
763                         mono_linterval_add_range (cfg, *i1, r->from, pos - 1);
764                         mono_linterval_add_range (cfg, *i2, pos, r->to);
765                 } else {
766                         /* Add it to the second child */
767                         mono_linterval_add_range (cfg, *i2, r->from, r->to);
768                 }
769         }
770 }
771
772 #if 1
773 #define LIVENESS_DEBUG(a) do { if (cfg->verbose_level > 1) do { a; } while (0); } while (0)
774 #define ENABLE_LIVENESS_DEBUG 1
775 #else
776 #define LIVENESS_DEBUG(a)
777 #endif
778
779 #ifdef ENABLE_LIVENESS2
780
781 static inline void
782 update_liveness2 (MonoCompile *cfg, MonoInst *ins, gboolean set_volatile, int inst_num, gint32 *last_use)
783 {
784         const char *spec = INS_INFO (ins->opcode);
785         int sreg;
786         int num_sregs, i;
787         int sregs [MONO_MAX_SRC_REGS];
788
789         LIVENESS_DEBUG (printf ("\t%x: ", inst_num); mono_print_ins (ins));
790
791         if (ins->opcode == OP_NOP)
792                 return;
793
794         /* DREG */
795         if ((spec [MONO_INST_DEST] != ' ') && get_vreg_to_inst (cfg, ins->dreg)) {
796                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
797                 int idx = var->inst_c0;
798                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
799
800                 if (MONO_IS_STORE_MEMBASE (ins)) {
801                         if (last_use [idx] == 0) {
802                                 LIVENESS_DEBUG (printf ("\tlast use of R%d set to %x\n", ins->dreg, inst_num));
803                                 last_use [idx] = inst_num;
804                         }
805                 } else {
806                         if (last_use [idx] > 0) {
807                                 LIVENESS_DEBUG (printf ("\tadd range to R%d: [%x, %x)\n", ins->dreg, inst_num, last_use [idx]));
808                                 mono_linterval_add_range (cfg, vi->interval, inst_num, last_use [idx]);
809                                 last_use [idx] = 0;
810                         }
811                         else {
812                                 /* Try dead code elimination */
813                                 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)) {
814                                         LIVENESS_DEBUG (printf ("\tdead def of R%d, eliminated\n", ins->dreg));
815                                         ins->opcode = OP_NOP;
816                                         ins->dreg = -1;
817                                         MONO_INST_NULLIFY_SREGS (ins);
818                                         return;
819                                 }
820
821                                 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));
822                                 mono_linterval_add_range (cfg, vi->interval, inst_num, inst_num + 1);
823                         }
824                 }
825         }
826
827         /* SREGs */
828         num_sregs = mono_inst_get_src_registers (ins, sregs);
829         for (i = 0; i < num_sregs; ++i) {
830                 sreg = sregs [i];
831                 if ((spec [MONO_INST_SRC1 + i] != ' ') && get_vreg_to_inst (cfg, sreg)) {
832                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
833                         int idx = var->inst_c0;
834
835                         if (last_use [idx] == 0) {
836                                 LIVENESS_DEBUG (printf ("\tlast use of R%d set to %x\n", sreg, inst_num));
837                                 last_use [idx] = inst_num;
838                         }
839                 }
840         }
841 }
842
843 static void
844 mono_analyze_liveness2 (MonoCompile *cfg)
845 {
846         int bnum, idx, i, j, nins, max, max_vars, block_from, block_to, pos, reverse_len;
847         gint32 *last_use;
848         static guint32 disabled = -1;
849         MonoInst **reverse;
850
851         if (disabled == -1)
852                 disabled = g_getenv ("DISABLED") != NULL;
853
854         if (disabled)
855                 return;
856
857         LIVENESS_DEBUG (printf ("LIVENESS 2 %s\n", mono_method_full_name (cfg->method, TRUE)));
858
859         /*
860         if (strstr (cfg->method->name, "test_") != cfg->method->name)
861                 return;
862         */
863
864         max_vars = cfg->num_varinfo;
865         last_use = g_new0 (gint32, max_vars);
866
867         reverse_len = 1024;
868         reverse = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * reverse_len);
869
870         for (idx = 0; idx < max_vars; ++idx) {
871                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
872
873                 vi->interval = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
874         }
875
876         /*
877          * Process bblocks in reverse order, so the addition of new live ranges
878          * to the intervals is faster.
879          */
880         for (bnum = cfg->num_bblocks - 1; bnum >= 0; --bnum) {
881                 MonoBasicBlock *bb = cfg->bblocks [bnum];
882                 MonoInst *ins;
883
884                 block_from = (bb->dfn << 16) + 1; /* so pos > 0 */
885                 if (bnum < cfg->num_bblocks - 1)
886                         /* Beginning of the next bblock */
887                         block_to = (cfg->bblocks [bnum + 1]->dfn << 16) + 1;
888                 else
889                         block_to = (bb->dfn << 16) + 0xffff;
890
891                 LIVENESS_DEBUG (printf ("LIVENESS BLOCK BB%d:\n", bb->block_num));
892
893                 memset (last_use, 0, max_vars * sizeof (gint32));
894                 
895                 /* For variables in bb->live_out, set last_use to block_to */
896
897                 max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK);
898                 for (j = 0; j < max; ++j) {
899                         gsize bits_out;
900                         int k;
901
902                         bits_out = mono_bitset_get_fast (bb->live_out_set, j);
903                         k = (j * BITS_PER_CHUNK);       
904                         while (bits_out) {
905                                 if (bits_out & 1) {
906                                         LIVENESS_DEBUG (printf ("Var R%d live at exit, set last_use to %x\n", cfg->varinfo [k]->dreg, block_to));
907                                         last_use [k] = block_to;
908                                 }
909                                 bits_out >>= 1;
910                                 k ++;
911                         }
912                 }
913
914                 if (cfg->ret)
915                         last_use [cfg->ret->inst_c0] = block_to;
916
917                 for (nins = 0, pos = block_from, ins = bb->code; ins; ins = ins->next, ++nins, ++pos) {
918                         if (nins >= reverse_len) {
919                                 int new_reverse_len = reverse_len * 2;
920                                 MonoInst **new_reverse = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * new_reverse_len);
921                                 memcpy (new_reverse, reverse, sizeof (MonoInst*) * reverse_len);
922                                 reverse = new_reverse;
923                                 reverse_len = new_reverse_len;
924                         }
925
926                         reverse [nins] = ins;
927                 }
928
929                 /* Process instructions backwards */
930                 for (i = nins - 1; i >= 0; --i) {
931                         MonoInst *ins = (MonoInst*)reverse [i];
932
933                         update_liveness2 (cfg, ins, FALSE, pos, last_use);
934
935                         pos --;
936                 }
937
938                 for (idx = 0; idx < max_vars; ++idx) {
939                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
940
941                         if (last_use [idx] != 0) {
942                                 /* Live at exit, not written -> live on enter */
943                                 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]));
944                                 mono_linterval_add_range (cfg, vi->interval, block_from, last_use [idx]);
945                         }
946                 }
947         }
948
949         /*
950          * Arguments need to have their live ranges extended to the beginning of
951          * the method to account for the arg reg/memory -> global register copies
952          * in the prolog (bug #74992).
953          */
954         for (i = 0; i < max_vars; i ++) {
955                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
956                 if (cfg->varinfo [vi->idx]->opcode == OP_ARG)
957                         mono_linterval_add_range (cfg, vi->interval, 0, 1);
958         }
959
960 #if 0
961         for (idx = 0; idx < max_vars; ++idx) {
962                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
963                 
964                 LIVENESS_DEBUG (printf ("LIVENESS R%d: ", cfg->varinfo [idx]->dreg));
965                 LIVENESS_DEBUG (mono_linterval_print (vi->interval));
966                 LIVENESS_DEBUG (printf ("\n"));
967         }
968 #endif
969
970         g_free (last_use);
971 }
972
973 #endif
974
975 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
976
977 static inline void
978 update_liveness_gc (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, gint32 *last_use, MonoMethodVar **vreg_to_varinfo, GSList **callsites)
979 {
980         if (ins->opcode == OP_GC_LIVENESS_DEF || ins->opcode == OP_GC_LIVENESS_USE) {
981                 int vreg = ins->inst_c1;
982                 MonoMethodVar *vi = vreg_to_varinfo [vreg];
983                 int idx = vi->idx;
984                 int pc_offset = ins->backend.pc_offset;
985
986                 LIVENESS_DEBUG (printf ("\t%x: ", pc_offset); mono_print_ins (ins));
987
988                 if (ins->opcode == OP_GC_LIVENESS_DEF) {
989                         if (last_use [idx] > 0) {
990                                 LIVENESS_DEBUG (printf ("\tadd range to R%d: [%x, %x)\n", vreg, pc_offset, last_use [idx]));
991                                 last_use [idx] = 0;
992                         }
993                 } else {
994                         if (last_use [idx] == 0) {
995                                 LIVENESS_DEBUG (printf ("\tlast use of R%d set to %x\n", vreg, pc_offset));
996                                 last_use [idx] = pc_offset;
997                         }
998                 }
999         } else if (ins->opcode == OP_GC_PARAM_SLOT_LIVENESS_DEF) {
1000                 GCCallSite *last;
1001
1002                 /* Add it to the last callsite */
1003                 g_assert (*callsites);
1004                 last = (*callsites)->data;
1005                 last->param_slots = g_slist_prepend_mempool (cfg->mempool, last->param_slots, ins);
1006         } else if (ins->flags & MONO_INST_GC_CALLSITE) {
1007                 GCCallSite *callsite = mono_mempool_alloc0 (cfg->mempool, sizeof (GCCallSite));
1008                 int i;
1009
1010                 LIVENESS_DEBUG (printf ("\t%x: ", ins->backend.pc_offset); mono_print_ins (ins));
1011                 LIVENESS_DEBUG (printf ("\t\tlive: "));
1012
1013                 callsite->bb = bb;
1014                 callsite->liveness = mono_mempool_alloc0 (cfg->mempool, ALIGN_TO (cfg->num_varinfo, 8) / 8);
1015                 callsite->pc_offset = ins->backend.pc_offset;
1016                 for (i = 0; i < cfg->num_varinfo; ++i) {
1017                         if (last_use [i] != 0) {
1018                                 LIVENESS_DEBUG (printf ("R%d", MONO_VARINFO (cfg, i)->vreg));
1019                                 callsite->liveness [i / 8] |= (1 << (i % 8));
1020                         }
1021                 }
1022                 LIVENESS_DEBUG (printf ("\n"));
1023                 *callsites = g_slist_prepend_mempool (cfg->mempool, *callsites, callsite);
1024         }
1025 }
1026
1027 static inline int
1028 get_vreg_from_var (MonoCompile *cfg, MonoInst *var)
1029 {
1030         if (var->opcode == OP_REGVAR)
1031                 /* dreg contains a hreg, but inst_c0 still contains the var index */
1032                 return MONO_VARINFO (cfg, var->inst_c0)->vreg;
1033         else
1034                 /* dreg still contains the vreg */
1035                 return var->dreg;
1036 }
1037
1038 /*
1039  * mono_analyze_liveness_gc:
1040  *
1041  *   Compute liveness bitmaps for each call site.
1042  * This function is a modified version of mono_analyze_liveness2 ().
1043  */
1044 void
1045 mono_analyze_liveness_gc (MonoCompile *cfg)
1046 {
1047         int idx, i, j, nins, max, max_vars, block_from, block_to, pos, reverse_len;
1048         gint32 *last_use;
1049         MonoInst **reverse;
1050         MonoMethodVar **vreg_to_varinfo = NULL;
1051         MonoBasicBlock *bb;
1052         GSList *callsites;
1053
1054         LIVENESS_DEBUG (printf ("\n------------ GC LIVENESS: ----------\n"));
1055
1056         max_vars = cfg->num_varinfo;
1057         last_use = g_new0 (gint32, max_vars);
1058
1059         /*
1060          * var->inst_c0 no longer contains the variable index, so compute a mapping now.
1061          */
1062         vreg_to_varinfo = g_new0 (MonoMethodVar*, cfg->next_vreg);
1063         for (idx = 0; idx < max_vars; ++idx) {
1064                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
1065
1066                 vreg_to_varinfo [vi->vreg] = vi;
1067         }
1068
1069         reverse_len = 1024;
1070         reverse = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * reverse_len);
1071
1072         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1073                 MonoInst *ins;
1074
1075                 block_from = bb->real_native_offset;
1076                 block_to = bb->native_offset + bb->native_length;
1077
1078                 LIVENESS_DEBUG (printf ("GC LIVENESS BB%d:\n", bb->block_num));
1079
1080                 if (!bb->code)
1081                         continue;
1082
1083                 memset (last_use, 0, max_vars * sizeof (gint32));
1084                 
1085                 /* For variables in bb->live_out, set last_use to block_to */
1086
1087                 max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK);
1088                 for (j = 0; j < max; ++j) {
1089                         gsize bits_out;
1090                         int k;
1091
1092                         if (!bb->live_out_set)
1093                                 /* The variables used in this bblock are volatile anyway */
1094                                 continue;
1095
1096                         bits_out = mono_bitset_get_fast (bb->live_out_set, j);
1097                         k = (j * BITS_PER_CHUNK);       
1098                         while (bits_out) {
1099                                 if ((bits_out & 1) && cfg->varinfo [k]->flags & MONO_INST_GC_TRACK) {
1100                                         int vreg = get_vreg_from_var (cfg, cfg->varinfo [k]);
1101                                         LIVENESS_DEBUG (printf ("Var R%d live at exit, last_use set to %x.\n", vreg, block_to));
1102                                         last_use [k] = block_to;
1103                                 }
1104                                 bits_out >>= 1;
1105                                 k ++;
1106                         }
1107                 }
1108
1109                 for (nins = 0, pos = block_from, ins = bb->code; ins; ins = ins->next, ++nins, ++pos) {
1110                         if (nins >= reverse_len) {
1111                                 int new_reverse_len = reverse_len * 2;
1112                                 MonoInst **new_reverse = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * new_reverse_len);
1113                                 memcpy (new_reverse, reverse, sizeof (MonoInst*) * reverse_len);
1114                                 reverse = new_reverse;
1115                                 reverse_len = new_reverse_len;
1116                         }
1117
1118                         reverse [nins] = ins;
1119                 }
1120
1121                 /* Process instructions backwards */
1122                 callsites = NULL;
1123                 for (i = nins - 1; i >= 0; --i) {
1124                         MonoInst *ins = (MonoInst*)reverse [i];
1125
1126                         update_liveness_gc (cfg, bb, ins, last_use, vreg_to_varinfo, &callsites);
1127                 }
1128                 /* The callsites should already be sorted by pc offset because we added them backwards */
1129                 bb->gc_callsites = callsites;
1130         }
1131
1132         g_free (last_use);
1133         g_free (vreg_to_varinfo);
1134 }
1135
1136 #endif /* DISABLE_JIT */