2 * linear-scan.c: linbear scan register allocation
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Miguel de Icaza (miguel@ximian.com)
8 * (C) 2001 Ximian, Inc.
18 //#define MNAME "nest_test"
21 #define DEGUG_LIVENESS
26 mono_bitset_mp_new (MonoMemPool *mp, guint32 max_size)
28 int size = mono_bitset_alloc_size (max_size, 0);
31 mem = mono_mempool_alloc0 (mp, size);
32 return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
36 mono_bitset_print (MonoBitSet *set)
41 for (i = 0; i < mono_bitset_size (set); i++) {
43 if (mono_bitset_test (set, i))
51 mono_update_live_range (MonoFlowGraph *cfg, int varnum, int block_num, int tree_pos)
53 MonoVarInfo *vi = &g_array_index (cfg->varinfo, MonoVarInfo, varnum);
54 guint32 abs_pos = (block_num << 16) | tree_pos;
56 if (vi->range.first_use.abs_pos > abs_pos)
57 vi->range.first_use.abs_pos = abs_pos;
59 if (vi->range.last_use.abs_pos < abs_pos)
60 vi->range.last_use.abs_pos = abs_pos;
64 mono_update_live_info (MonoFlowGraph *cfg)
68 for (i = 0; i < cfg->block_count; i++) {
69 MonoBBlock *bb = &cfg->bblocks [i];
71 for (j = cfg->varinfo->len - 1; j > 0; j--) {
73 if (mono_bitset_test (bb->live_in_set, j))
74 mono_update_live_range (cfg, j, bb->num, 0);
76 if (mono_bitset_test (bb->live_out_set, j))
77 mono_update_live_range (cfg, j, bb->num, bb->forest->len);
83 mono_update_gen_set (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree *tree,
84 int tnum, MonoBitSet *set)
88 case MB_TERM_REMOTE_STIND_I1:
89 case MB_TERM_REMOTE_STIND_I2:
90 case MB_TERM_REMOTE_STIND_I4:
91 case MB_TERM_REMOTE_STIND_I8:
92 case MB_TERM_REMOTE_STIND_R4:
93 case MB_TERM_REMOTE_STIND_R8:
94 case MB_TERM_REMOTE_STIND_OBJ:
95 case MB_TERM_STIND_I1:
96 case MB_TERM_STIND_I2:
97 case MB_TERM_STIND_I4:
98 case MB_TERM_STIND_I8:
99 case MB_TERM_STIND_R4:
100 case MB_TERM_STIND_R8:
101 case MB_TERM_STIND_OBJ:
102 if (tree->left->op != MB_TERM_ADDR_L)
103 mono_update_gen_set (cfg, bb, tree->left, tnum, set);
105 mono_update_live_range (cfg, tree->left->data.i,
109 mono_update_gen_set (cfg, bb, tree->left, tnum, set);
115 mono_update_gen_set (cfg, bb, tree->right, tnum, set);
117 if (tree->op == MB_TERM_ADDR_L) {
118 mono_update_live_range (cfg, tree->data.i, bb->num, tnum);
119 mono_bitset_set (set, tree->data.i);
124 mono_analyze_liveness (MonoFlowGraph *cfg)
126 MonoBitSet *old_live_in_set, *old_live_out_set;
129 int i, j , max_vars = cfg->varinfo->len;
131 #ifdef DEGUG_LIVENESS
132 int debug = !strcmp (cfg->method->name, MNAME);
134 printf ("LIVENLESS %s.%s:%s\n", cfg->method->klass->name_space,
135 cfg->method->klass->name, cfg->method->name);
138 old_live_in_set = mono_bitset_new (max_vars, 0);
139 old_live_out_set = mono_bitset_new (max_vars, 0);
141 for (i = 0; i < cfg->block_count; i++) {
142 MonoBBlock *bb = &cfg->bblocks [i];
144 bb->gen_set = mono_bitset_mp_new (cfg->mp, max_vars);
145 bb->kill_set = mono_bitset_mp_new (cfg->mp, max_vars);
146 bb->live_in_set = mono_bitset_mp_new (cfg->mp, max_vars);
147 bb->live_out_set = mono_bitset_mp_new (cfg->mp, max_vars);
149 for (j = 0; j < bb->forest->len; j++) {
150 MBTree *t1 = (MBTree *) g_ptr_array_index (bb->forest, j);
152 mono_bitset_clear_all (old_live_in_set);
153 mono_update_gen_set (cfg, bb, t1, j, old_live_in_set);
154 mono_bitset_sub (old_live_in_set, bb->kill_set);
155 mono_bitset_union (bb->gen_set, old_live_in_set);
158 case MB_TERM_REMOTE_STIND_I1:
159 case MB_TERM_REMOTE_STIND_I2:
160 case MB_TERM_REMOTE_STIND_I4:
161 case MB_TERM_REMOTE_STIND_I8:
162 case MB_TERM_REMOTE_STIND_R4:
163 case MB_TERM_REMOTE_STIND_R8:
164 case MB_TERM_REMOTE_STIND_OBJ:
165 case MB_TERM_STIND_I1:
166 case MB_TERM_STIND_I2:
167 case MB_TERM_STIND_I4:
168 case MB_TERM_STIND_I8:
169 case MB_TERM_STIND_R4:
170 case MB_TERM_STIND_R8:
171 case MB_TERM_STIND_OBJ:
172 if (t1->left->op == MB_TERM_ADDR_L)
173 mono_bitset_set (bb->kill_set, t1->left->data.i);
178 #ifdef DEGUG_LIVENESS
180 printf ("BLOCK %d (", bb->num);
181 for (l = bb->succ; l; l = l->next) {
182 MonoBBlock *t = (MonoBBlock *)l->data;
183 printf ("%d, ", t->num);
186 printf ("GEN %d: ", i); mono_bitset_print (bb->gen_set); printf ("\n");
187 printf ("KILL %d: ", i); mono_bitset_print (bb->kill_set); printf ("\n");
195 for (i = cfg->block_count - 1; i >= 0; i--) {
196 MonoBBlock *bb = &cfg->bblocks [i];
198 mono_bitset_copyto (bb->live_in_set, old_live_in_set);
199 mono_bitset_copyto (bb->live_out_set, old_live_out_set);
201 mono_bitset_copyto (bb->live_out_set, bb->live_in_set);
202 mono_bitset_sub (bb->live_in_set, bb->kill_set);
203 mono_bitset_union (bb->live_in_set, bb->gen_set);
205 mono_bitset_clear_all (bb->live_out_set);
207 for (l = bb->succ; l; l = l->next) {
208 MonoBBlock *t = (MonoBBlock *)l->data;
209 mono_bitset_union (bb->live_out_set, t->live_in_set);
212 if (!(mono_bitset_equal (old_live_in_set, bb->live_in_set) &&
213 mono_bitset_equal (old_live_out_set, bb->live_out_set)))
219 mono_bitset_free (old_live_in_set);
220 mono_bitset_free (old_live_out_set);
223 #ifdef DEGUG_LIVENESS
225 for (i = 0; i < cfg->block_count; i++) {
226 MonoBBlock *bb = &cfg->bblocks [i];
228 printf ("LIVE IN %d: ", i);
229 mono_bitset_print (bb->live_in_set);
231 printf ("LIVE OUT %d: ", i);
232 mono_bitset_print (bb->live_out_set);
240 mono_varlist_insert_sorted (GList *list, MonoVarInfo *vi, gboolean sort_end)
245 return g_list_prepend (NULL, vi);
247 for (l = list; l; l = l->next) {
248 MonoVarInfo *v = (MonoVarInfo *)l->data;
251 if (vi->range.last_use.abs_pos <= v->range.last_use.abs_pos) {
252 list = g_list_insert_before (list, l, vi);
256 if (vi->range.first_use.abs_pos <= v->range.first_use.abs_pos) {
257 list = g_list_insert_before (list, l, vi);
263 list = g_list_append (list, vi);
269 mono_linear_scan (MonoFlowGraph *cfg, guint32 *used_mask)
271 GList *l, *ranges = NULL;
272 GList *active = NULL;
277 MonoMethod *m = cfg->method;
278 int debug = !strcmp (cfg->method->name, MNAME);
281 printf ("VARINFO for %s.%s:%s\n", m->klass->name_space, m->klass->name, m->name);
284 mono_analyze_liveness (cfg);
285 mono_update_live_info (cfg);
287 for (i = 1; i < cfg->varinfo->len; i++) {
288 MonoVarInfo *vi = &g_array_index (cfg->varinfo, MonoVarInfo, i);
291 if (vi->range.first_use.abs_pos > vi->range.last_use.abs_pos)
294 /* we can only allocate 32 bit values */
295 if (vi->isvolatile || (vi->type != VAL_I32 && vi->type != VAL_POINTER))
298 ranges = mono_varlist_insert_sorted (ranges, vi, FALSE);
304 for (l = ranges; l; l = l->next) {
305 MonoVarInfo *vi = (MonoVarInfo *)l->data;
307 printf ("VAR %d %08x %08x\n", vi->varnum, vi->range.first_use.abs_pos,
308 vi->range.last_use.abs_pos);
313 /* we can use 2 registers for global allocation */
314 regs = g_list_prepend (regs, (gpointer)X86_EBX);
315 regs = g_list_prepend (regs, (gpointer)X86_ESI);
317 max_regs = g_list_length (regs);
321 for (l = ranges; l; l = l->next) {
322 MonoVarInfo *vi = (MonoVarInfo *)l->data;
326 printf ("START %2d %08x %08x\n", vi->varnum, vi->range.first_use.abs_pos,
327 vi->range.last_use.abs_pos);
329 /* expire old intervals in active */
331 MonoVarInfo *v = (MonoVarInfo *)active->data;
333 if (v->range.last_use.abs_pos >= vi->range.first_use.abs_pos)
338 printf ("EXPIR %2d %08x %08x\n", v->varnum,
339 v->range.first_use.abs_pos, v->range.last_use.abs_pos);
341 active = g_list_remove_link (active, active);
342 regs = g_list_prepend (regs, (gpointer)v->reg);
345 if (active && g_list_length (active) == max_regs) {
348 GList *a = g_list_nth (active, max_regs - 1);
349 MonoVarInfo *v = (MonoVarInfo *)a->data;
351 if (v->range.last_use.abs_pos > vi->range.last_use.abs_pos) {
354 active = g_list_remove_link (active, a);
355 active = mono_varlist_insert_sorted (active, vi, TRUE);
358 printf ("SPILL0 %2d %08x %08x\n", v->varnum,
359 v->range.first_use.abs_pos, v->range.last_use.abs_pos);
364 printf ("SPILL1 %2d %08x %08x\n", vi->varnum,
365 vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
370 /* assign register */
374 vi->reg = (int)regs->data;
376 *used_mask |= 1 << vi->reg;
378 regs = g_list_remove_link (regs, regs);
382 printf ("ADD %2d %08x %08x\n", vi->varnum,
383 vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
385 active = mono_varlist_insert_sorted (active, vi, TRUE);
392 for (a = active; a; a = a->next) {
393 MonoVarInfo *v = (MonoVarInfo *)a->data;
395 printf ("ACT %2d %08x %08x %d\n", v->varnum,
396 v->range.first_use.abs_pos, v->range.last_use.abs_pos, v->reg);
404 g_list_free (active);
405 g_list_free (ranges);