grammar updates
[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
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 #ifdef DEBUG_LIVENESS
33 static void
34 mono_bitset_print (MonoBitSet *set)
35 {
36         int i;
37
38         printf ("{");
39         for (i = 0; i < mono_bitset_size (set); i++) {
40
41                 if (mono_bitset_test (set, i))
42                         printf ("%d, ", i);
43
44         }
45         printf ("}");
46 }
47 #endif
48
49 static void
50 update_live_range (MonoCompile *cfg, int idx, int block_dfn, int tree_pos)
51 {
52         MonoLiveRange *range = &MONO_VARINFO (cfg, idx)->range;
53         guint32 abs_pos = (block_dfn << 16) | tree_pos;
54
55         if (range->first_use.abs_pos > abs_pos)
56                 range->first_use.abs_pos = abs_pos;
57
58         if (range->last_use.abs_pos < abs_pos)
59                 range->last_use.abs_pos = abs_pos;
60 }
61
62 static void
63 update_gen_kill_set (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *inst, int inst_num)
64 {
65         int arity = mono_burg_arity [inst->opcode];
66         int max_vars = cfg->num_varinfo;
67
68         if (arity)
69                 update_gen_kill_set (cfg, bb, inst->inst_i0, inst_num);
70
71         if (arity > 1)
72                 update_gen_kill_set (cfg, bb, inst->inst_i1, inst_num);
73
74         if (inst->ssa_op == MONO_SSA_LOAD) {
75                 int idx = inst->inst_i0->inst_c0;
76                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
77                 g_assert (idx < max_vars);
78                 update_live_range (cfg, idx, bb->dfn, inst_num); 
79                 if (!mono_bitset_test (bb->kill_set, idx))
80                         mono_bitset_set (bb->gen_set, idx);
81                 vi->spill_costs += 1 + (bb->nesting * 2);
82         } else if (inst->ssa_op == MONO_SSA_STORE) {
83                 int idx = inst->inst_i0->inst_c0;
84                 MonoMethodVar *vi = MONO_VARINFO (cfg, idx);
85                 g_assert (idx < max_vars);
86                 g_assert (inst->inst_i1->opcode != OP_PHI);
87
88                 update_live_range (cfg, idx, bb->dfn, inst_num); 
89                 mono_bitset_set (bb->kill_set, idx);
90                 vi->spill_costs += 1 + (bb->nesting * 2);
91         }
92
93
94 /* generic liveness analysis code. CFG specific parts are 
95  * in update_gen_kill_set()
96  */
97 void
98 mono_analyze_liveness (MonoCompile *cfg)
99 {
100         MonoBitSet *old_live_in_set, *old_live_out_set;
101         gboolean changes;
102         int i, j, max_vars = cfg->num_varinfo;
103
104 #ifdef DEBUG_LIVENESS
105         printf ("LIVENLESS %s\n", mono_method_full_name (cfg->method, TRUE));
106 #endif
107
108         g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS));
109
110         cfg->comp_done |= MONO_COMP_LIVENESS;
111         
112         if (max_vars == 0)
113                 return;
114
115         for (i = 0; i < cfg->num_bblocks; ++i) {
116                 MonoBasicBlock *bb = cfg->bblocks [i];
117
118                 bb->gen_set = mono_bitset_mp_new (cfg->mempool, max_vars);
119                 bb->kill_set = mono_bitset_mp_new (cfg->mempool, max_vars);
120                 bb->live_in_set = mono_bitset_mp_new (cfg->mempool, max_vars);
121                 bb->live_out_set = mono_bitset_mp_new (cfg->mempool, max_vars);
122         }
123
124         for (i = 0; i < cfg->num_bblocks; ++i) {
125                 MonoBasicBlock *bb = cfg->bblocks [i];
126                 MonoInst *inst;
127                 int tree_num;
128
129                 for (tree_num = 0, inst = bb->code; inst; inst = inst->next, tree_num++) {
130                         //mono_print_tree (inst); printf ("\n");
131                         update_gen_kill_set (cfg, bb, inst, tree_num);
132                 }
133
134 #ifdef DEBUG_LIVENESS
135                 printf ("BLOCK BB%d (", bb->block_num);
136                 for (j = 0; j < bb->out_count; j++) 
137                         printf ("BB%d, ", bb->out_bb [j]->block_num);
138                 
139                 printf (")\n");
140                 printf ("GEN  BB%d: ", bb->block_num); mono_bitset_print (bb->gen_set); printf ("\n");
141                 printf ("KILL BB%d: ", bb->block_num); mono_bitset_print (bb->kill_set); printf ("\n");
142 #endif
143         }
144
145         old_live_in_set = mono_bitset_new (max_vars, 0);
146         old_live_out_set = mono_bitset_new (max_vars, 0);
147  
148         do {
149                 changes = FALSE;
150
151                 for (i = cfg->num_bblocks - 1; i >= 0; i--) {
152                         MonoBasicBlock *bb = cfg->bblocks [i];
153
154                         mono_bitset_copyto (bb->live_in_set, old_live_in_set);
155                         mono_bitset_copyto (bb->live_out_set, old_live_out_set);
156
157                         mono_bitset_copyto (bb->live_out_set, bb->live_in_set);
158                         mono_bitset_sub (bb->live_in_set, bb->kill_set);
159                         mono_bitset_union (bb->live_in_set, bb->gen_set);
160
161                         mono_bitset_clear_all (bb->live_out_set);
162                         
163                         for (j = 0; j < bb->out_count; j++) 
164                                 mono_bitset_union (bb->live_out_set, bb->out_bb [j]->live_in_set);
165
166                         if (!(mono_bitset_equal (old_live_in_set, bb->live_in_set) &&
167                               mono_bitset_equal (old_live_out_set, bb->live_out_set)))
168                                 changes = TRUE;
169                 }
170
171         } while (changes);
172
173         mono_bitset_free (old_live_in_set);
174         mono_bitset_free (old_live_out_set);
175
176         for (i = 0; i < cfg->num_bblocks; ++i) {
177                 MonoBasicBlock *bb = cfg->bblocks [i];
178
179                 for (j = max_vars - 1; j >= 0; j--) {
180                         
181                         if (mono_bitset_test (bb->live_in_set, j))
182                                 update_live_range (cfg, j, bb->dfn, 0);
183
184                         if (mono_bitset_test (bb->live_out_set, j))
185                                 update_live_range (cfg, j, bb->dfn, 0xffff);
186                 } 
187         } 
188
189 #ifdef DEBUG_LIVENESS
190         for (i = cfg->num_bblocks - 1; i >= 0; i--) {
191                 MonoBasicBlock *bb = cfg->bblocks [i];
192                 
193                 printf ("LIVE IN  BB%d: ", bb->block_num); 
194                 mono_bitset_print (bb->live_in_set); 
195                 printf ("\n");
196                 printf ("LIVE OUT BB%d: ", bb->block_num); 
197                 mono_bitset_print (bb->live_out_set); 
198                 printf ("\n");
199         }
200 #endif
201 }
202