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