2006-01-03 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 DEBUG_LIVENESS
15
16 extern guint8 mono_burg_arity [];
17
18 /* mono_bitset_mp_new:
19  * 
20  * allocates a MonoBitSet inside a memory pool
21  */
22 static MonoBitSet* 
23 mono_bitset_mp_new (MonoMemPool *mp,  guint32 max_size)
24 {
25         int size = mono_bitset_alloc_size (max_size, 0);
26         gpointer mem;
27
28         mem = mono_mempool_alloc0 (mp, size);
29         return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
30 }
31
32 G_GNUC_UNUSED static void
33 mono_bitset_print (MonoBitSet *set)
34 {
35         int i;
36
37         printf ("{");
38         for (i = 0; i < mono_bitset_size (set); i++) {
39
40                 if (mono_bitset_test (set, i))
41                         printf ("%d, ", i);
42
43         }
44         printf ("}\n");
45 }
46
47 static inline void
48 update_live_range (MonoCompile *cfg, int idx, int block_dfn, int tree_pos)
49 {
50         MonoLiveRange *range = &MONO_VARINFO (cfg, idx)->range;
51         guint32 abs_pos = (block_dfn << 16) | tree_pos;
52
53         if (range->first_use.abs_pos > abs_pos)
54                 range->first_use.abs_pos = abs_pos;
55
56         if (range->last_use.abs_pos < abs_pos)
57                 range->last_use.abs_pos = abs_pos;
58 }
59
60 static void
61 update_gen_kill_set (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
62 {
63         int arity = mono_burg_arity [inst->opcode];
64         int max_vars = cfg->num_varinfo;
65
66         if (arity)
67                 update_gen_kill_set (cfg, bb, inst->inst_i0, inst_num);
68
69         if (arity > 1)
70                 update_gen_kill_set (cfg, bb, inst->inst_i1, inst_num);
71
72         if ((inst->ssa_op & MONO_SSA_LOAD_STORE) || (inst->opcode == OP_DUMMY_STORE)) {
73                 MonoLocalVariableList* affected_variables;
74                 MonoLocalVariableList local_affected_variable;
75                 
76                 if (cfg->aliasing_info == NULL) {
77                         if ((inst->ssa_op == MONO_SSA_LOAD) || (inst->ssa_op == MONO_SSA_STORE) || (inst->opcode == OP_DUMMY_STORE)) {
78                                 local_affected_variable.variable_index = inst->inst_i0->inst_c0;
79                                 local_affected_variable.next = NULL;
80                                 affected_variables = &local_affected_variable;
81                         } else {
82                                 affected_variables = NULL;
83                         }
84                 } else {
85                         affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (cfg->aliasing_info, inst);
86                 }
87                 
88                 if (inst->ssa_op & MONO_SSA_LOAD) {
89                         MonoLocalVariableList* affected_variable = affected_variables;
90                         while (affected_variable != NULL) {
91                                 int idx = affected_variable->variable_index;
92                                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
93                                 g_assert (idx < max_vars);
94                                 if ((bb->region != -1) && !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
95                                         /*
96                                          * Variables used in exception regions can't be allocated to 
97                                          * registers.
98                                          */
99                                         cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
100                                 }
101                                 update_live_range (cfg, idx, bb->dfn, inst_num); 
102                                 if (!mono_bitset_test (bb->kill_set, idx))
103                                         mono_bitset_set (bb->gen_set, idx);
104                                 if (inst->ssa_op == MONO_SSA_LOAD)
105                                         vi->spill_costs += 1 + (bb->nesting * 2);
106                                 
107                                 affected_variable = affected_variable->next;
108                         }
109                 } else if ((inst->ssa_op == MONO_SSA_STORE) || (inst->opcode == OP_DUMMY_STORE)) {
110                         MonoLocalVariableList* affected_variable = affected_variables;
111                         while (affected_variable != NULL) {
112                                 int idx = affected_variable->variable_index;
113                                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
114                                 g_assert (idx < max_vars);
115                                 //if (arity > 0)
116                                         //g_assert (inst->inst_i1->opcode != OP_PHI);
117                                 if ((bb->region != -1) && !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
118                                         /*
119                                          * Variables used in exception regions can't be allocated to 
120                                          * registers.
121                                          */
122                                         cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
123                                 }
124                                 update_live_range (cfg, idx, bb->dfn, inst_num); 
125                                 mono_bitset_set (bb->kill_set, idx);
126                                 if (inst->ssa_op == MONO_SSA_STORE)
127                                         vi->spill_costs += 1 + (bb->nesting * 2);
128                                 
129                                 affected_variable = affected_variable->next;
130                         }
131                 }
132         } else if (inst->opcode == CEE_JMP) {
133                 /* Keep arguments live! */
134                 int i;
135                 for (i = 0; i < cfg->num_varinfo; i++) {
136                         if (cfg->varinfo [i]->opcode == OP_ARG) {
137                                 if (!mono_bitset_test (bb->kill_set, i))
138                                         mono_bitset_set (bb->gen_set, i);
139                         }
140                 }
141         }
142
143
144 static void
145 update_volatile (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
146 {
147         int arity = mono_burg_arity [inst->opcode];
148         int max_vars = cfg->num_varinfo;
149
150         if (arity)
151                 update_volatile (cfg, bb, inst->inst_i0, inst_num);
152
153         if (arity > 1)
154                 update_volatile (cfg, bb, inst->inst_i1, inst_num);
155
156         if (inst->ssa_op & MONO_SSA_LOAD_STORE) {
157                 MonoLocalVariableList* affected_variables;
158                 MonoLocalVariableList local_affected_variable;
159                 
160                 if (cfg->aliasing_info == NULL) {
161                         if ((inst->ssa_op == MONO_SSA_LOAD) || (inst->ssa_op == MONO_SSA_STORE)) {
162                                 local_affected_variable.variable_index = inst->inst_i0->inst_c0;
163                                 local_affected_variable.next = NULL;
164                                 affected_variables = &local_affected_variable;
165                         } else {
166                                 affected_variables = NULL;
167                         }
168                 } else {
169                         affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (cfg->aliasing_info, inst);
170                 }
171                 
172                 while (affected_variables != NULL) {
173                         int idx = affected_variables->variable_index;
174                         MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
175                         g_assert (idx < max_vars);
176                         cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
177                         
178                         affected_variables = affected_variables->next;
179                 }
180         }
181
182
183 static void
184 visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, GSList **visited)
185 {
186         int i, tree_num;
187         MonoInst *inst;
188
189         if (g_slist_find (*visited, bb))
190                 return;
191
192         if (cfg->aliasing_info != NULL)
193                 mono_aliasing_initialize_code_traversal (cfg->aliasing_info, bb);
194         
195         for (tree_num = 0, inst = bb->code; inst; inst = inst->next, tree_num++) {
196                 update_volatile (cfg, bb, inst, tree_num);
197         }
198
199         *visited = g_slist_append (*visited, bb);
200
201         /* 
202          * Need to visit all bblocks reachable from this one since they can be
203          * reached during exception handling.
204          */
205         for (i = 0; i < bb->out_count; ++i) {
206                 visit_bb (cfg, bb->out_bb [i], visited);
207         }
208 }
209
210 static void
211 handle_exception_clauses (MonoCompile *cfg)
212 {
213         MonoBasicBlock *bb;
214         GSList *visited = NULL;
215
216         /*
217          * Variables in exception handler register cannot be allocated to registers
218          * so make them volatile. See bug #42136. This will not be neccessary when
219          * the back ends could guarantee that the variables will be in the
220          * correct registers when a handler is called.
221          * This includes try blocks too, since a variable in a try block might be
222          * accessed after an exception handler has been run.
223          */
224         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
225
226                 if (bb->region == -1 || MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))
227                         continue;
228
229                 visit_bb (cfg, bb, &visited);
230         }
231         g_slist_free (visited);
232 }
233
234 /* generic liveness analysis code. CFG specific parts are 
235  * in update_gen_kill_set()
236  */
237 void
238 mono_analyze_liveness (MonoCompile *cfg)
239 {
240         MonoBitSet *old_live_in_set, *old_live_out_set, *tmp_in_set;
241         gboolean changes;
242         int i, j, max_vars = cfg->num_varinfo;
243         int iterations, out_iter, in_iter;
244         gboolean *changed_in, *changed_out, *new_changed_in, *in_worklist;
245         MonoBasicBlock **worklist;
246         guint32 l_begin, l_end;
247         static int count = 0;
248
249 #ifdef DEBUG_LIVENESS
250         printf ("LIVENESS %s\n", mono_method_full_name (cfg->method, TRUE));
251 #endif
252
253         g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS));
254
255         cfg->comp_done |= MONO_COMP_LIVENESS;
256         
257         if (max_vars == 0)
258                 return;
259
260         for (i = 0; i < cfg->num_bblocks; ++i) {
261                 MonoBasicBlock *bb = cfg->bblocks [i];
262
263                 bb->gen_set = mono_bitset_mp_new (cfg->mempool, max_vars);
264                 bb->kill_set = mono_bitset_mp_new (cfg->mempool, max_vars);
265                 bb->live_in_set = mono_bitset_mp_new (cfg->mempool, max_vars);
266                 bb->live_out_set = mono_bitset_mp_new (cfg->mempool, max_vars);
267         }
268         for (i = 0; i < max_vars; i ++) {
269                 MONO_VARINFO (cfg, i)->range.first_use.abs_pos = ~ 0;
270                 MONO_VARINFO (cfg, i)->range.last_use .abs_pos =   0;
271                 MONO_VARINFO (cfg, i)->spill_costs = 0;
272         }
273
274         for (i = 0; i < cfg->num_bblocks; ++i) {
275                 MonoBasicBlock *bb = cfg->bblocks [i];
276                 MonoInst *inst;
277                 int tree_num;
278
279                 if (cfg->aliasing_info != NULL)
280                         mono_aliasing_initialize_code_traversal (cfg->aliasing_info, bb);
281                 
282                 for (tree_num = 0, inst = bb->code; inst; inst = inst->next, tree_num++) {
283 #ifdef DEBUG_LIVENESS
284                         mono_print_tree (inst); printf ("\n");
285 #endif
286                         update_gen_kill_set (cfg, bb, inst, tree_num);
287                 }
288
289 #ifdef DEBUG_LIVENESS
290                 printf ("BLOCK BB%d (", bb->block_num);
291                 for (j = 0; j < bb->out_count; j++) 
292                         printf ("BB%d, ", bb->out_bb [j]->block_num);
293                 
294                 printf (")\n");
295                 printf ("GEN  BB%d: ", bb->block_num); mono_bitset_print (bb->gen_set);
296                 printf ("KILL BB%d: ", bb->block_num); mono_bitset_print (bb->kill_set);
297 #endif
298         }
299
300         old_live_in_set = mono_bitset_new (max_vars, 0);
301         old_live_out_set = mono_bitset_new (max_vars, 0);
302         tmp_in_set = mono_bitset_new (max_vars, 0);
303         changed_in = g_new0 (gboolean, cfg->num_bblocks + 1);
304         changed_out = g_new0 (gboolean, cfg->num_bblocks + 1);
305         in_worklist = g_new0 (gboolean, cfg->num_bblocks + 1);
306         new_changed_in = g_new0 (gboolean, cfg->num_bblocks + 1);
307
308         for (i = 0; i < cfg->num_bblocks + 1; ++i) {
309                 changed_in [i] = TRUE;
310                 changed_out [i] = TRUE;
311         }
312
313         count ++;
314
315         worklist = g_new0 (MonoBasicBlock *, cfg->num_bblocks + 1);
316         l_begin = 0;
317         l_end = 0;
318
319         for (i = cfg->num_bblocks - 1; i >= 0; i--) {
320                 MonoBasicBlock *bb = cfg->bblocks [i];
321
322                 worklist [l_end ++] = bb;
323                 in_worklist [bb->dfn] = TRUE;
324         }
325
326         iterations = 0;
327         out_iter = 0;
328         in_iter = 0;
329         do {
330                 changes = FALSE;
331                 iterations ++;
332
333                 while (l_begin != l_end) {
334                         MonoBasicBlock *bb = worklist [l_begin ++];
335
336                         in_worklist [bb->dfn] = FALSE;
337
338                         if (l_begin == cfg->num_bblocks + 1)
339                                 l_begin = 0;
340
341                         if (bb->out_count > 0) {
342                                 out_iter ++;
343                                 mono_bitset_copyto (bb->live_out_set, old_live_out_set);
344
345                                 for (j = 0; j < bb->out_count; j++) {
346                                         MonoBasicBlock *out_bb = bb->out_bb [j];
347
348                                         mono_bitset_copyto (out_bb->live_out_set, tmp_in_set);
349                                         mono_bitset_sub (tmp_in_set, out_bb->kill_set);
350                                         mono_bitset_union (tmp_in_set, out_bb->gen_set);
351
352                                         mono_bitset_union (bb->live_out_set, tmp_in_set);
353
354                                 }
355                                 
356                                 changed_out [bb->dfn] = !mono_bitset_equal (old_live_out_set, bb->live_out_set);
357                                 if (changed_out [bb->dfn]) {
358                                         for (j = 0; j < bb->in_count; j++) {
359                                                 MonoBasicBlock *in_bb = bb->in_bb [j];
360                                                 /* 
361                                                  * Some basic blocks do not seem to be in the 
362                                                  * cfg->bblocks array...
363                                                  */
364                                                 if (in_bb->live_in_set)
365                                                         if (!in_worklist [in_bb->dfn]) {
366                                                                 worklist [l_end ++] = in_bb;
367                                                                 if (l_end == cfg->num_bblocks + 1)
368                                                                         l_end = 0;
369                                                                 in_worklist [in_bb->dfn] = TRUE;
370                                                         }
371                                         }
372
373                                         changes = TRUE;
374                                 }
375                         }
376                 }
377         } while (changes);
378
379         //printf ("IT: %d %d %d.\n", iterations, in_iter, out_iter);
380
381         mono_bitset_free (old_live_in_set);
382         mono_bitset_free (old_live_out_set);
383         mono_bitset_free (tmp_in_set);
384
385         g_free (changed_in);
386         g_free (changed_out);
387         g_free (new_changed_in);
388         g_free (worklist);
389         g_free (in_worklist);
390
391         for (i = cfg->num_bblocks - 1; i >= 0; i--) {
392                 MonoBasicBlock *bb = cfg->bblocks [i];
393
394                 mono_bitset_copyto (bb->live_out_set, bb->live_in_set);
395                 mono_bitset_sub (bb->live_in_set, bb->kill_set);
396                 mono_bitset_union (bb->live_in_set, bb->gen_set);
397         }
398
399         /*
400          * This code can be slow for large methods so inline the calls to
401          * mono_bitset_test.
402          */
403         for (i = 0; i < cfg->num_bblocks; ++i) {
404                 MonoBasicBlock *bb = cfg->bblocks [i];
405                 guint32 rem;
406
407                 rem = max_vars % 32;
408                 for (j = 0; j < (max_vars / 32) + 1; ++j) {
409                         guint32 bits_in;
410                         guint32 bits_out;
411                         int k, nbits;
412
413                         if (j > (max_vars / 32))
414                                 break;
415                         else
416                                 if (j == (max_vars / 32))
417                                         nbits = rem;
418                                 else
419                                         nbits = 32;
420
421                         bits_in = mono_bitset_test_bulk (bb->live_in_set, j * 32);
422                         bits_out = mono_bitset_test_bulk (bb->live_out_set, j * 32);
423                         for (k = 0; k < nbits; ++k) {
424                                 if (bits_in & (1 << k))
425                                         update_live_range (cfg, (j * 32) + k, bb->dfn, 0);
426                                 if (bits_out & (1 << k))
427                                         update_live_range (cfg, (j * 32) + k, bb->dfn, 0xffff);
428                         }
429                 }
430         }
431
432         /* todo: remove code when we have verified that the liveness for try/catch blocks
433          * works perfectly 
434          */
435         /* 
436          * Currently, this can't be commented out since exception blocks are not
437          * processed during liveness analysis.
438          */
439         handle_exception_clauses (cfg);
440
441         /*
442          * Arguments need to have their live ranges extended to the beginning of
443          * the method to account for the arg reg/memory -> global register copies
444          * in the prolog (bug #74992).
445          */
446
447         for (i = 0; i < max_vars; i ++) {
448                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
449                 if (cfg->varinfo [vi->idx]->opcode == OP_ARG)
450                         vi->range.first_use.abs_pos = 0;
451         }
452
453 #ifdef DEBUG_LIVENESS
454         for (i = cfg->num_bblocks - 1; i >= 0; i--) {
455                 MonoBasicBlock *bb = cfg->bblocks [i];
456                 
457                 printf ("LIVE IN  BB%d: ", bb->block_num); 
458                 mono_bitset_print (bb->live_in_set); 
459                 printf ("LIVE OUT BB%d: ", bb->block_num); 
460                 mono_bitset_print (bb->live_out_set); 
461         }
462 #endif
463 }