2 * liveness.c: liveness analysis
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2002 Ximian, Inc.
14 //#define DEBUG_LIVENESS
16 extern guint8 mono_burg_arity [];
18 /* mono_bitset_mp_new:
20 * allocates a MonoBitSet inside a memory pool
23 mono_bitset_mp_new (MonoMemPool *mp, guint32 max_size)
25 int size = mono_bitset_alloc_size (max_size, 0);
28 mem = mono_mempool_alloc0 (mp, size);
29 return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
32 G_GNUC_UNUSED static void
33 mono_bitset_print (MonoBitSet *set)
38 for (i = 0; i < mono_bitset_size (set); i++) {
40 if (mono_bitset_test (set, i))
48 update_live_range (MonoCompile *cfg, int idx, int block_dfn, int tree_pos)
50 MonoLiveRange *range = &MONO_VARINFO (cfg, idx)->range;
51 guint32 abs_pos = (block_dfn << 16) | tree_pos;
53 if (range->first_use.abs_pos > abs_pos)
54 range->first_use.abs_pos = abs_pos;
56 if (range->last_use.abs_pos < abs_pos)
57 range->last_use.abs_pos = abs_pos;
61 update_gen_kill_set (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
63 int arity = mono_burg_arity [inst->opcode];
64 int max_vars = cfg->num_varinfo;
67 update_gen_kill_set (cfg, bb, inst->inst_i0, inst_num);
70 update_gen_kill_set (cfg, bb, inst->inst_i1, inst_num);
72 if ((inst->ssa_op & MONO_SSA_LOAD_STORE) || (inst->opcode == OP_DUMMY_STORE)) {
73 MonoLocalVariableList* affected_variables;
74 MonoLocalVariableList local_affected_variable;
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;
82 affected_variables = NULL;
85 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (cfg->aliasing_info, inst);
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)) {
96 * Variables used in exception regions can't be allocated to
99 cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
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);
107 affected_variable = affected_variable->next;
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);
116 //g_assert (inst->inst_i1->opcode != OP_PHI);
117 if ((bb->region != -1) && !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
119 * Variables used in exception regions can't be allocated to
122 cfg->varinfo [vi->idx]->flags |= MONO_INST_VOLATILE;
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);
129 affected_variable = affected_variable->next;
132 } else if (inst->opcode == CEE_JMP) {
133 /* Keep arguments live! */
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);
145 update_volatile (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
147 int arity = mono_burg_arity [inst->opcode];
148 int max_vars = cfg->num_varinfo;
151 update_volatile (cfg, bb, inst->inst_i0, inst_num);
154 update_volatile (cfg, bb, inst->inst_i1, inst_num);
156 if (inst->ssa_op & MONO_SSA_LOAD_STORE) {
157 MonoLocalVariableList* affected_variables;
158 MonoLocalVariableList local_affected_variable;
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;
166 affected_variables = NULL;
169 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (cfg->aliasing_info, inst);
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;
178 affected_variables = affected_variables->next;
184 visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, GSList **visited)
189 if (g_slist_find (*visited, bb))
192 if (cfg->aliasing_info != NULL)
193 mono_aliasing_initialize_code_traversal (cfg->aliasing_info, bb);
195 for (tree_num = 0, inst = bb->code; inst; inst = inst->next, tree_num++) {
196 update_volatile (cfg, bb, inst, tree_num);
199 *visited = g_slist_append (*visited, bb);
202 * Need to visit all bblocks reachable from this one since they can be
203 * reached during exception handling.
205 for (i = 0; i < bb->out_count; ++i) {
206 visit_bb (cfg, bb->out_bb [i], visited);
211 handle_exception_clauses (MonoCompile *cfg)
214 GSList *visited = NULL;
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.
224 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
226 if (bb->region == -1 || MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))
229 visit_bb (cfg, bb, &visited);
231 g_slist_free (visited);
234 /* generic liveness analysis code. CFG specific parts are
235 * in update_gen_kill_set()
238 mono_analyze_liveness (MonoCompile *cfg)
240 MonoBitSet *old_live_in_set, *old_live_out_set, *tmp_in_set;
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;
249 #ifdef DEBUG_LIVENESS
250 printf ("LIVENESS %s\n", mono_method_full_name (cfg->method, TRUE));
253 g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS));
255 cfg->comp_done |= MONO_COMP_LIVENESS;
260 for (i = 0; i < cfg->num_bblocks; ++i) {
261 MonoBasicBlock *bb = cfg->bblocks [i];
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);
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;
274 for (i = 0; i < cfg->num_bblocks; ++i) {
275 MonoBasicBlock *bb = cfg->bblocks [i];
279 if (cfg->aliasing_info != NULL)
280 mono_aliasing_initialize_code_traversal (cfg->aliasing_info, bb);
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");
286 update_gen_kill_set (cfg, bb, inst, tree_num);
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);
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);
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);
308 for (i = 0; i < cfg->num_bblocks + 1; ++i) {
309 changed_in [i] = TRUE;
310 changed_out [i] = TRUE;
315 worklist = g_new0 (MonoBasicBlock *, cfg->num_bblocks + 1);
319 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
320 MonoBasicBlock *bb = cfg->bblocks [i];
322 worklist [l_end ++] = bb;
323 in_worklist [bb->dfn] = TRUE;
333 while (l_begin != l_end) {
334 MonoBasicBlock *bb = worklist [l_begin ++];
336 in_worklist [bb->dfn] = FALSE;
338 if (l_begin == cfg->num_bblocks + 1)
341 if (bb->out_count > 0) {
343 mono_bitset_copyto (bb->live_out_set, old_live_out_set);
345 for (j = 0; j < bb->out_count; j++) {
346 MonoBasicBlock *out_bb = bb->out_bb [j];
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);
352 mono_bitset_union (bb->live_out_set, tmp_in_set);
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];
361 * Some basic blocks do not seem to be in the
362 * cfg->bblocks array...
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)
369 in_worklist [in_bb->dfn] = TRUE;
379 //printf ("IT: %d %d %d.\n", iterations, in_iter, out_iter);
381 mono_bitset_free (old_live_in_set);
382 mono_bitset_free (old_live_out_set);
383 mono_bitset_free (tmp_in_set);
386 g_free (changed_out);
387 g_free (new_changed_in);
389 g_free (in_worklist);
391 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
392 MonoBasicBlock *bb = cfg->bblocks [i];
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);
400 * This code can be slow for large methods so inline the calls to
403 for (i = 0; i < cfg->num_bblocks; ++i) {
404 MonoBasicBlock *bb = cfg->bblocks [i];
408 for (j = 0; j < (max_vars / 32) + 1; ++j) {
413 if (j > (max_vars / 32))
416 if (j == (max_vars / 32))
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);
432 /* todo: remove code when we have verified that the liveness for try/catch blocks
436 * Currently, this can't be commented out since exception blocks are not
437 * processed during liveness analysis.
439 handle_exception_clauses (cfg);
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).
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;
453 #ifdef DEBUG_LIVENESS
454 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
455 MonoBasicBlock *bb = cfg->bblocks [i];
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);