2 * liveness.c: liveness analysis
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2002 Ximian, Inc.
13 //#define DEBUG_LIVENESS
15 extern guint8 mono_burg_arity [];
17 /* mono_bitset_mp_new:
19 * allocates a MonoBitSet inside a memory pool
22 mono_bitset_mp_new (MonoMemPool *mp, guint32 max_size)
24 int size = mono_bitset_alloc_size (max_size, 0);
27 mem = mono_mempool_alloc0 (mp, size);
28 return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
31 G_GNUC_UNUSED static void
32 mono_bitset_print (MonoBitSet *set)
37 for (i = 0; i < mono_bitset_size (set); i++) {
39 if (mono_bitset_test (set, i))
47 update_live_range (MonoCompile *cfg, int idx, int block_dfn, int tree_pos)
49 MonoLiveRange *range = &MONO_VARINFO (cfg, idx)->range;
50 guint32 abs_pos = (block_dfn << 16) | tree_pos;
52 if (range->first_use.abs_pos > abs_pos)
53 range->first_use.abs_pos = abs_pos;
55 if (range->last_use.abs_pos < abs_pos)
56 range->last_use.abs_pos = abs_pos;
60 update_gen_kill_set (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
62 int arity = mono_burg_arity [inst->opcode];
63 int max_vars = cfg->num_varinfo;
66 update_gen_kill_set (cfg, bb, inst->inst_i0, inst_num);
69 update_gen_kill_set (cfg, bb, inst->inst_i1, inst_num);
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)) {
77 * Variables used in exception regions can't be allocated to
80 cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
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);
91 g_assert (inst->inst_i1->opcode != OP_PHI);
92 if ((bb->region != -1) && !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
94 * Variables used in exception regions can't be allocated to
97 cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
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);
106 update_volatile (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
108 int arity = mono_burg_arity [inst->opcode];
109 int max_vars = cfg->num_varinfo;
112 update_volatile (cfg, bb, inst->inst_i0, inst_num);
115 update_volatile (cfg, bb, inst->inst_i1, inst_num);
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;
126 visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, GSList **visited)
131 if (g_slist_find (*visited, bb))
134 for (tree_num = 0, inst = bb->code; inst; inst = inst->next, tree_num++) {
135 update_volatile (cfg, bb, inst, tree_num);
138 *visited = g_slist_append (*visited, bb);
141 * Need to visit all bblocks reachable from this one since they can be
142 * reached during exception handling.
144 for (i = 0; i < bb->out_count; ++i) {
145 visit_bb (cfg, bb->out_bb [i], visited);
150 handle_exception_clauses (MonoCompile *cfg)
153 GSList *visited = NULL;
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.
163 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
165 if (bb->region == -1 || MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))
168 visit_bb (cfg, bb, &visited);
170 g_slist_free (visited);
173 /* generic liveness analysis code. CFG specific parts are
174 * in update_gen_kill_set()
177 mono_analyze_liveness (MonoCompile *cfg)
179 MonoBitSet *old_live_in_set, *old_live_out_set, *tmp_in_set;
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;
188 #ifdef DEBUG_LIVENESS
189 printf ("LIVENESS %s\n", mono_method_full_name (cfg->method, TRUE));
192 g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS));
194 cfg->comp_done |= MONO_COMP_LIVENESS;
199 for (i = 0; i < cfg->num_bblocks; ++i) {
200 MonoBasicBlock *bb = cfg->bblocks [i];
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);
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;
213 for (i = 0; i < cfg->num_bblocks; ++i) {
214 MonoBasicBlock *bb = cfg->bblocks [i];
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");
222 update_gen_kill_set (cfg, bb, inst, tree_num);
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);
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);
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);
244 for (i = 0; i < cfg->num_bblocks + 1; ++i) {
245 changed_in [i] = TRUE;
246 changed_out [i] = TRUE;
251 worklist = g_new0 (MonoBasicBlock *, cfg->num_bblocks + 1);
255 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
256 MonoBasicBlock *bb = cfg->bblocks [i];
258 worklist [l_end ++] = bb;
259 in_worklist [bb->dfn] = TRUE;
269 while (l_begin != l_end) {
270 MonoBasicBlock *bb = worklist [l_begin ++];
272 in_worklist [bb->dfn] = FALSE;
274 if (l_begin == cfg->num_bblocks + 1)
277 if (bb->out_count > 0) {
279 mono_bitset_copyto (bb->live_out_set, old_live_out_set);
281 for (j = 0; j < bb->out_count; j++) {
282 MonoBasicBlock *out_bb = bb->out_bb [j];
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);
288 mono_bitset_union (bb->live_out_set, tmp_in_set);
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];
297 * Some basic blocks do not seem to be in the
298 * cfg->bblocks array...
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)
305 in_worklist [in_bb->dfn] = TRUE;
315 //printf ("IT: %d %d %d.\n", iterations, in_iter, out_iter);
317 mono_bitset_free (old_live_in_set);
318 mono_bitset_free (old_live_out_set);
319 mono_bitset_free (tmp_in_set);
322 g_free (changed_out);
323 g_free (new_changed_in);
325 g_free (in_worklist);
327 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
328 MonoBasicBlock *bb = cfg->bblocks [i];
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);
336 * This code can be slow for large methods so inline the calls to
339 for (i = 0; i < cfg->num_bblocks; ++i) {
340 MonoBasicBlock *bb = cfg->bblocks [i];
344 for (j = 0; j < (max_vars / 32) + 1; ++j) {
349 if (j > (max_vars / 32))
352 if (j == (max_vars / 32))
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);
368 handle_exception_clauses (cfg);
370 #ifdef DEBUG_LIVENESS
371 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
372 MonoBasicBlock *bb = cfg->bblocks [i];
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);