Wed Feb 22 10:31:25 CET 2006 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini-codegen.c
1 /*
2  * mini-codegen.c: Arch independent code generation functionality
3  *
4  * (C) 2003 Ximian, Inc.
5  */
6
7 #include <string.h>
8 #include <math.h>
9 #include <unistd.h>
10
11 #include <mono/metadata/appdomain.h>
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/threads.h>
14 #include <mono/metadata/profiler-private.h>
15 #include <mono/utils/mono-math.h>
16
17 #include "mini.h"
18 #include "trace.h"
19 #include "inssel.h"
20 #include "mini-arch.h"
21
22 #define DEBUG(a) if (cfg->verbose_level > 1) a
23
24 #if defined(__x86_64__)
25 const char * const amd64_desc [OP_LAST];
26 static const char*const * ins_spec = amd64_desc;
27 #elif defined(__sparc__) || defined(sparc)
28 const char * const sparc_desc [OP_LAST];
29 static const char*const * ins_spec = sparc_desc;
30 #elif defined(__i386__)
31 extern const char * const pentium_desc [OP_LAST];
32 static const char*const * ins_spec = pentium_desc;
33 #elif defined(__ia64__)
34 const char * const ia64_desc [OP_LAST];
35 static const char*const * ins_spec = ia64_desc;
36 #elif defined(__arm__)
37 const char * const arm_cpu_desc [OP_LAST];
38 static const char*const * ins_spec = arm_cpu_desc;
39 #elif defined(__s390x__)
40 const char * const s390x_cpu_desc [OP_LAST];
41 static const char*const * ins_spec = s390x_cpu_desc;
42 #elif defined(__s390__)
43 const char * const s390_cpu_desc [OP_LAST];
44 static const char*const * ins_spec = s390_cpu_desc;
45 #else
46 #error "Not implemented"
47 #endif
48
49 #define use_fpstack MONO_ARCH_USE_FPSTACK
50
51 const char*
52 mono_regname_full (int reg, gboolean fp)
53 {
54         if (fp)
55                 return mono_arch_fregname (reg);
56         else
57                 return mono_arch_regname (reg);
58 }
59
60 void
61 mono_call_inst_add_outarg_reg (MonoCallInst *call, int vreg, int hreg, gboolean fp)
62 {
63         guint32 regpair;
64
65         regpair = (((guint32)hreg) << 24) + vreg;
66         if (fp)
67                 call->out_freg_args = g_slist_append (call->out_freg_args, (gpointer)(gssize)(regpair));
68         else
69                 call->out_ireg_args = g_slist_append (call->out_ireg_args, (gpointer)(gssize)(regpair));
70 }
71
72 /*
73  * returns the offset used by spillvar. It allocates a new
74  * spill variable if necessary. 
75  */
76 static int
77 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
78 {
79         MonoSpillInfo **si, *info;
80         int i = 0;
81
82         si = &cfg->spill_info; 
83         
84         while (i <= spillvar) {
85
86                 if (!*si) {
87                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
88                         info->next = NULL;
89                         if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
90                                 info->offset = cfg->stack_offset;
91                                 cfg->stack_offset += sizeof (gpointer);
92                         } else {
93                                 cfg->stack_offset += sizeof (gpointer);
94                                 info->offset = - cfg->stack_offset;
95                         }
96                 }
97
98                 if (i == spillvar)
99                         return (*si)->offset;
100
101                 i++;
102                 si = &(*si)->next;
103         }
104
105         g_assert_not_reached ();
106         return 0;
107 }
108
109 /*
110  * returns the offset used by spillvar. It allocates a new
111  * spill float variable if necessary. 
112  * (same as mono_spillvar_offset but for float)
113  */
114 static int
115 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
116 {
117         MonoSpillInfo **si, *info;
118         int i = 0;
119
120         si = &cfg->spill_info_float; 
121         
122         while (i <= spillvar) {
123
124                 if (!*si) {
125                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
126                         info->next = NULL;
127                         if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
128                                 cfg->stack_offset += 7;
129                                 cfg->stack_offset &= ~7;
130                                 info->offset = cfg->stack_offset;
131                                 cfg->stack_offset += sizeof (double);
132                         } else {
133                                 /* FIXME: align */
134                                 cfg->stack_offset += sizeof (double);
135                                 info->offset = - cfg->stack_offset;
136                         }
137                 }
138
139                 if (i == spillvar)
140                         return (*si)->offset;
141
142                 i++;
143                 si = &(*si)->next;
144         }
145
146         g_assert_not_reached ();
147         return 0;
148 }
149
150 /*
151  * Creates a store for spilled floating point items
152  */
153 static MonoInst*
154 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
155 {
156         MonoInst *store;
157         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
158         store->sreg1 = reg;
159         store->inst_destbasereg = cfg->frame_reg;
160         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
161
162         DEBUG (g_print ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
163         return store;
164 }
165
166 /*
167  * Creates a load for spilled floating point items 
168  */
169 static MonoInst*
170 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
171 {
172         MonoInst *load;
173         MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
174         load->dreg = reg;
175         load->inst_basereg = cfg->frame_reg;
176         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
177
178         DEBUG (g_print ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
179         return load;
180 }
181
182 #define regmask(reg) (((regmask_t)1) << (reg))
183
184 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
185 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
186 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
187 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
188 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
189 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
190 #define ireg_is_freeable(r) is_local_ireg ((r))
191 #define freg_is_freeable(r) is_hard_freg ((r))
192
193 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
194 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
195 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
196 #define rassign(cfg,reg,fp) ((fp) ? (cfg)->rs->fassign [(reg)] : (cfg)->rs->iassign [(reg)])
197 #define sreg1_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_SRC1] == 'f')
198 #define sreg2_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_SRC2] == 'f')
199
200 #ifdef MONO_ARCH_INST_IS_FLOAT
201 #define dreg_is_fp(ins)  (MONO_ARCH_INST_IS_FLOAT (ins_spec [(ins)->opcode] [MONO_INST_DEST]))
202 #else
203 #define dreg_is_fp(ins)  (ins_spec [(ins)->opcode] [MONO_INST_DEST] == 'f')
204 #endif
205
206 #define regpair_reg2_mask(desc,hreg1) ((MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1) != -1) ? (regmask (MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1))) : MONO_ARCH_CALLEE_REGS)
207
208 #ifdef MONO_ARCH_IS_GLOBAL_IREG
209 #undef is_global_ireg
210 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
211 #endif
212
213 typedef struct {
214         int born_in;
215         int killed_in;
216         int last_use;
217         int prev_use;
218         int flags;              /* used to track fp spill/load */
219         regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
220 } RegTrack;
221
222 static void
223 print_ins (int i, MonoInst *ins)
224 {
225         const char *spec = ins_spec [ins->opcode];
226         g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
227         if (!spec)
228                 g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
229
230         if (spec [MONO_INST_DEST]) {
231                 gboolean fp = dreg_is_fp (ins);
232                 if (is_soft_reg (ins->dreg, fp)) {
233                         if (spec [MONO_INST_DEST] == 'b') {
234                                 if (ins->inst_offset == 0)
235                                         g_print (" [R%d] <-", ins->dreg);
236                                 else
237                                         g_print (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
238                         }
239                         else
240                                 g_print (" R%d <-", ins->dreg);
241                 } else if (spec [MONO_INST_DEST] == 'b') {
242                         if (ins->inst_offset == 0)
243                                 g_print (" [%s] <-", mono_arch_regname (ins->dreg));
244                         else
245                                 g_print (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
246                 } else
247                         g_print (" %s <-", mono_regname_full (ins->dreg, fp));
248         }
249         if (spec [MONO_INST_SRC1]) {
250                 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
251                 if (is_soft_reg (ins->sreg1, fp))
252                         g_print (" R%d", ins->sreg1);
253                 else if (spec [MONO_INST_SRC1] == 'b')
254                         g_print (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
255                 else
256                         g_print (" %s", mono_regname_full (ins->sreg1, fp));
257         }
258         if (spec [MONO_INST_SRC2]) {
259                 gboolean fp = (spec [MONO_INST_SRC2] == 'f');
260                 if (is_soft_reg (ins->sreg2, fp))
261                         g_print (" R%d", ins->sreg2);
262                 else
263                         g_print (" %s", mono_regname_full (ins->sreg2, fp));
264         }
265         if (spec [MONO_INST_CLOB])
266                 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
267         g_print ("\n");
268 }
269
270 static void
271 print_regtrack (RegTrack *t, int num)
272 {
273         int i;
274         char buf [32];
275         const char *r;
276         
277         for (i = 0; i < num; ++i) {
278                 if (!t [i].born_in)
279                         continue;
280                 if (i >= MONO_MAX_IREGS) {
281                         g_snprintf (buf, sizeof(buf), "R%d", i);
282                         r = buf;
283                 } else
284                         r = mono_arch_regname (i);
285                 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
286         }
287 }
288
289 typedef struct InstList InstList;
290
291 struct InstList {
292         InstList *prev;
293         InstList *next;
294         MonoInst *data;
295 };
296
297 static inline InstList*
298 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
299 {
300         InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
301         item->data = data;
302         item->prev = NULL;
303         item->next = list;
304         if (list)
305                 list->prev = item;
306         return item;
307 }
308
309 /*
310  * Force the spilling of the variable in the symbolic register 'reg'.
311  */
312 static int
313 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg, gboolean fp)
314 {
315         MonoInst *load;
316         int i, sel, spill;
317         int *assign, *symbolic;
318
319         if (fp) {
320                 assign = cfg->rs->fassign;
321                 symbolic = cfg->rs->fsymbolic;
322         }
323         else {
324                 assign = cfg->rs->iassign;
325                 symbolic = cfg->rs->isymbolic;
326         }       
327         
328         sel = assign [reg];
329         /*i = cfg->rs->isymbolic [sel];
330         g_assert (i == reg);*/
331         i = reg;
332         spill = ++cfg->spill_count;
333         assign [i] = -spill - 1;
334         if (fp)
335                 mono_regstate_free_float (cfg->rs, sel);
336         else
337                 mono_regstate_free_int (cfg->rs, sel);
338         /* we need to create a spill var and insert a load to sel after the current instruction */
339         if (fp)
340                 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
341         else
342                 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
343         load->dreg = sel;
344         load->inst_basereg = cfg->frame_reg;
345         load->inst_offset = mono_spillvar_offset (cfg, spill);
346         if (item->prev) {
347                 while (ins->next != item->prev->data)
348                         ins = ins->next;
349         }
350         load->next = ins->next;
351         ins->next = load;
352         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
353         if (fp)
354                 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
355         else
356                 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
357         g_assert (i == sel);
358
359         return sel;
360 }
361
362 /* This isn't defined on older glib versions and on some platforms */
363 #ifndef G_GUINT64_FORMAT
364 #define G_GUINT64_FORMAT "ul"
365 #endif
366
367 static int
368 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_t regmask, int reg, gboolean fp)
369 {
370         MonoInst *load;
371         int i, sel, spill;
372         int *assign, *symbolic;
373
374         if (fp) {
375                 assign = cfg->rs->fassign;
376                 symbolic = cfg->rs->fsymbolic;
377         }
378         else {
379                 assign = cfg->rs->iassign;
380                 symbolic = cfg->rs->isymbolic;
381         }
382
383         DEBUG (g_print ("\tstart regmask to assign R%d: 0x%08" G_GUINT64_FORMAT " (R%d <- R%d R%d)\n", reg, (guint64)regmask, ins->dreg, ins->sreg1, ins->sreg2));
384         /* exclude the registers in the current instruction */
385         if ((sreg1_is_fp (ins) == fp) && (reg != ins->sreg1) && (reg_is_freeable (ins->sreg1, fp) || (is_soft_reg (ins->sreg1, fp) && rassign (cfg, ins->sreg1, fp) >= 0))) {
386                 if (is_soft_reg (ins->sreg1, fp))
387                         regmask &= ~ (regmask (rassign (cfg, ins->sreg1, fp)));
388                 else
389                         regmask &= ~ (regmask (ins->sreg1));
390                 DEBUG (g_print ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
391         }
392         if ((sreg2_is_fp (ins) == fp) && (reg != ins->sreg2) && (reg_is_freeable (ins->sreg2, fp) || (is_soft_reg (ins->sreg2, fp) && rassign (cfg, ins->sreg2, fp) >= 0))) {
393                 if (is_soft_reg (ins->sreg2, fp))
394                         regmask &= ~ (regmask (rassign (cfg, ins->sreg2, fp)));
395                 else
396                         regmask &= ~ (regmask (ins->sreg2));
397                 DEBUG (g_print ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
398         }
399         if ((dreg_is_fp (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
400                 regmask &= ~ (regmask (ins->dreg));
401                 DEBUG (g_print ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
402         }
403
404         DEBUG (g_print ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
405         g_assert (regmask); /* need at least a register we can free */
406         sel = -1;
407         /* we should track prev_use and spill the register that's farther */
408         if (fp) {
409                 for (i = 0; i < MONO_MAX_FREGS; ++i) {
410                         if (regmask & (regmask (i))) {
411                                 sel = i;
412                                 DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
413                                 break;
414                         }
415                 }
416
417                 i = cfg->rs->fsymbolic [sel];
418                 spill = ++cfg->spill_count;
419                 cfg->rs->fassign [i] = -spill - 1;
420                 mono_regstate_free_float (cfg->rs, sel);
421         }
422         else {
423                 for (i = 0; i < MONO_MAX_IREGS; ++i) {
424                         if (regmask & (regmask (i))) {
425                                 sel = i;
426                                 DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
427                                 break;
428                         }
429                 }
430
431                 i = cfg->rs->isymbolic [sel];
432                 spill = ++cfg->spill_count;
433                 cfg->rs->iassign [i] = -spill - 1;
434                 mono_regstate_free_int (cfg->rs, sel);
435         }
436
437         /* we need to create a spill var and insert a load to sel after the current instruction */
438         MONO_INST_NEW (cfg, load, fp ? OP_LOADR8_MEMBASE : OP_LOAD_MEMBASE);
439         load->dreg = sel;
440         load->inst_basereg = cfg->frame_reg;
441         load->inst_offset = mono_spillvar_offset (cfg, spill);
442         if (item->prev) {
443                 while (ins->next != item->prev->data)
444                         ins = ins->next;
445         }
446         load->next = ins->next;
447         ins->next = load;
448         DEBUG (g_print ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
449         if (fp)
450                 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
451         else
452                 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
453         g_assert (i == sel);
454         
455         return sel;
456 }
457
458 static void
459 free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
460 {
461         if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
462                 DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
463                 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
464                 mono_regstate_free_int (cfg->rs, hreg);
465         }
466 }
467
468 static void
469 free_up_reg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg, gboolean fp)
470 {
471         if (fp) {
472                 if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
473                         DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
474                         get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
475                         mono_regstate_free_float (cfg->rs, hreg);
476                 }
477         }
478         else {
479                 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
480                         DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
481                         get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
482                         mono_regstate_free_int (cfg->rs, hreg);
483                 }
484         }
485 }
486
487 static MonoInst*
488 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins, const unsigned char *ip, gboolean fp)
489 {
490         MonoInst *copy;
491
492         if (fp)
493                 MONO_INST_NEW (cfg, copy, OP_FMOVE);
494         else
495                 MONO_INST_NEW (cfg, copy, OP_MOVE);
496
497         copy->dreg = dest;
498         copy->sreg1 = src;
499         copy->cil_code = ip;
500         if (ins) {
501                 copy->next = ins->next;
502                 copy->cil_code = ins->cil_code;
503                 ins->next = copy;
504         }
505         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
506         return copy;
507 }
508
509 static MonoInst*
510 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins, gboolean fp)
511 {
512         MonoInst *store;
513         MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
514         store->sreg1 = reg;
515         store->inst_destbasereg = cfg->frame_reg;
516         store->inst_offset = mono_spillvar_offset (cfg, spill);
517         if (ins) {
518                 store->next = ins->next;
519                 ins->next = store;
520         }
521         DEBUG (g_print ("\tSPILLED STORE (%d at 0x%08lx(%%ebp)) R%d (from %s)\n", spill, (long)store->inst_offset, prev_reg, mono_regname_full (reg, fp)));
522         return store;
523 }
524
525 static void
526 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
527 {
528         MonoInst *prev;
529         if (item->next) {
530                 prev = item->next->data;
531
532                 while (prev->next != ins)
533                         prev = prev->next;
534                 to_insert->next = ins;
535                 prev->next = to_insert;
536         } else {
537                 to_insert->next = ins;
538         }
539         /* 
540          * needed otherwise in the next instruction we can add an ins to the 
541          * end and that would get past this instruction.
542          */
543         item->data = to_insert; 
544 }
545
546 /* flags used in reginfo->flags */
547 enum {
548         MONO_FP_NEEDS_LOAD_SPILL        = regmask (0),
549         MONO_FP_NEEDS_SPILL                     = regmask (1),
550         MONO_FP_NEEDS_LOAD                      = regmask (2)
551 };
552
553 static int
554 alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
555 {
556         int val;
557
558         if (info && info->preferred_mask) {
559                 val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
560                 if (val >= 0) {
561                         DEBUG (g_print ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
562                         return val;
563                 }
564         }
565
566         val = mono_regstate_alloc_int (cfg->rs, dest_mask);
567         if (val < 0)
568                 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
569
570         return val;
571 }
572
573 static int
574 alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg)
575 {
576         int val;
577
578         val = mono_regstate_alloc_float (cfg->rs, dest_mask);
579
580         if (val < 0) {
581                 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
582         }
583
584         return val;
585 }
586
587 static int
588 alloc_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
589 {
590         if (fp)
591                 return alloc_float_reg (cfg, tmp, ins, dest_mask, sym_reg);
592         else
593                 return alloc_int_reg (cfg, tmp, ins, dest_mask, sym_reg, info);
594 }
595
596 static inline void
597 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
598 {
599         if (fp) {
600                 g_assert (reg >= MONO_MAX_FREGS);
601                 g_assert (hreg < MONO_MAX_FREGS);
602                 g_assert (! is_global_freg (hreg));
603
604                 rs->fassign [reg] = hreg;
605                 rs->fsymbolic [hreg] = reg;
606                 rs->ffree_mask &= ~ (regmask (hreg));
607         }
608         else {
609                 g_assert (reg >= MONO_MAX_IREGS);
610                 g_assert (hreg < MONO_MAX_IREGS);
611                 g_assert (! is_global_ireg (hreg));
612
613                 rs->iassign [reg] = hreg;
614                 rs->isymbolic [hreg] = reg;
615                 rs->ifree_mask &= ~ (regmask (hreg));
616         }
617 }
618
619 static inline void
620 assign_ireg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg)
621 {
622         assign_reg (cfg, rs, reg, hreg, FALSE);
623 }
624
625 /*
626  * Local register allocation.
627  * We first scan the list of instructions and we save the liveness info of
628  * each register (when the register is first used, when it's value is set etc.).
629  * We also reverse the list of instructions (in the InstList list) because assigning
630  * registers backwards allows for more tricks to be used.
631  */
632 void
633 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
634 {
635         MonoInst *ins;
636         MonoRegState *rs = cfg->rs;
637         int i, val, fpcount;
638         RegTrack *reginfo, *reginfof;
639         RegTrack *reginfo1, *reginfo2, *reginfod;
640         InstList *tmp, *reversed = NULL;
641         const char *spec;
642         GList *fspill_list = NULL;
643         gboolean fp;
644         int fspill = 0;
645
646         if (!bb->code)
647                 return;
648
649         rs->next_vireg = bb->max_ireg;
650         rs->next_vfreg = bb->max_freg;
651         mono_regstate_assign (rs);
652         reginfo = g_malloc0 (sizeof (RegTrack) * rs->next_vireg);
653         reginfof = g_malloc0 (sizeof (RegTrack) * rs->next_vfreg);
654         rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
655         rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
656
657         if (use_fpstack)
658                 rs->ffree_mask = 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE));
659
660         ins = bb->code;
661
662         /*if (cfg->opt & MONO_OPT_COPYPROP)
663                 local_copy_prop (cfg, ins);*/
664
665         i = 1;
666         fpcount = 0;
667         DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
668         /* forward pass on the instructions to collect register liveness info */
669         while (ins) {
670                 spec = ins_spec [ins->opcode];
671
672                 if (!spec) {
673                         g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
674                 }
675                 
676                 DEBUG (print_ins (i, ins));
677
678                 /*
679                  * TRACK FP STACK
680                  */
681                 if (use_fpstack) {
682                         GList *spill;
683
684                         if (spec [MONO_INST_SRC1] == 'f') {
685                                 spill = g_list_first (fspill_list);
686                                 if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
687                                         reginfof [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
688                                         fspill_list = g_list_remove (fspill_list, spill->data);
689                                 } else
690                                         fpcount--;
691                         }
692
693                         if (spec [MONO_INST_SRC2] == 'f') {
694                                 spill = g_list_first (fspill_list);
695                                 if (spill) {
696                                         reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
697                                         fspill_list = g_list_remove (fspill_list, spill->data);
698                                         if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
699                                                 fspill++;
700                                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
701                                                 reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
702                                         }
703                                 } else
704                                         fpcount--;
705                         }
706
707                         if (dreg_is_fp (ins)) {
708                                 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
709                                         if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
710                                                 reginfof [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
711                                                 fspill++;
712                                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
713                                                 fpcount--;
714                                         }
715                                         fpcount++;
716                                 }
717                         }
718                 }
719
720                 if (spec [MONO_INST_SRC1]) {
721                         if (spec [MONO_INST_SRC1] == 'f')
722                                 reginfo1 = reginfof;
723                         else
724                                 reginfo1 = reginfo;
725                         reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
726                         reginfo1 [ins->sreg1].last_use = i;
727                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
728                                 /* The virtual register is allocated sequentially */
729                                 reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
730                                 reginfo1 [ins->sreg1 + 1].last_use = i;
731                                 if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
732                                         reginfo1 [ins->sreg1 + 1].born_in = i;
733                         }
734                 } else {
735                         ins->sreg1 = -1;
736                 }
737                 if (spec [MONO_INST_SRC2]) {
738                         if (spec [MONO_INST_SRC2] == 'f')
739                                 reginfo2 = reginfof;
740                         else
741                                 reginfo2 = reginfo;
742                         reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
743                         reginfo2 [ins->sreg2].last_use = i;
744                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
745                                 /* The virtual register is allocated sequentially */
746                                 reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
747                                 reginfo2 [ins->sreg2 + 1].last_use = i;
748                                 if (reginfo2 [ins->sreg2 + 1].born_in == 0 || reginfo2 [ins->sreg2 + 1].born_in > i)
749                                         reginfo2 [ins->sreg2 + 1].born_in = i;
750                         }
751                 } else {
752                         ins->sreg2 = -1;
753                 }
754                 if (spec [MONO_INST_DEST]) {
755                         int dest_dreg;
756
757                         if (dreg_is_fp (ins))
758                                 reginfod = reginfof;
759                         else
760                                 reginfod = reginfo;
761                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
762                                 reginfod [ins->dreg].killed_in = i;
763                         reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
764                         reginfod [ins->dreg].last_use = i;
765                         if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
766                                 reginfod [ins->dreg].born_in = i;
767
768                         dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
769                         if (dest_dreg != -1)
770                                 reginfod [ins->dreg].preferred_mask = (regmask (dest_dreg));
771
772                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
773                                 /* The virtual register is allocated sequentially */
774                                 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
775                                 reginfod [ins->dreg + 1].last_use = i;
776                                 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
777                                         reginfod [ins->dreg + 1].born_in = i;
778                                 if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
779                                         reginfod [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
780                         }
781                 } else {
782                         ins->dreg = -1;
783                 }
784
785                 if (spec [MONO_INST_CLOB] == 'c') {
786                         /* A call instruction implicitly uses all registers in call->out_ireg_args */
787
788                         MonoCallInst *call = (MonoCallInst*)ins;
789                         GSList *list;
790
791                         list = call->out_ireg_args;
792                         if (list) {
793                                 while (list) {
794                                         guint32 regpair;
795                                         int reg, hreg;
796
797                                         regpair = (guint32)(gssize)(list->data);
798                                         hreg = regpair >> 24;
799                                         reg = regpair & 0xffffff;
800
801                                         reginfo [reg].prev_use = reginfo [reg].last_use;
802                                         reginfo [reg].last_use = i;
803
804                                         list = g_slist_next (list);
805                                 }
806                         }
807
808                         list = call->out_freg_args;
809                         if (!use_fpstack && list) {
810                                 while (list) {
811                                         guint32 regpair;
812                                         int reg, hreg;
813
814                                         regpair = (guint32)(gssize)(list->data);
815                                         hreg = regpair >> 24;
816                                         reg = regpair & 0xffffff;
817
818                                         reginfof [reg].prev_use = reginfof [reg].last_use;
819                                         reginfof [reg].last_use = i;
820
821                                         list = g_slist_next (list);
822                                 }
823                         }
824                 }
825
826                 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
827                 ++i;
828                 ins = ins->next;
829         }
830
831         // todo: check if we have anything left on fp stack, in verify mode?
832         fspill = 0;
833
834         DEBUG (print_regtrack (reginfo, rs->next_vireg));
835         DEBUG (print_regtrack (reginfof, rs->next_vfreg));
836         tmp = reversed;
837         while (tmp) {
838                 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
839                 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
840                 int dreg_high, sreg1_high;
841                 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
842                 const unsigned char *ip;
843                 --i;
844                 ins = tmp->data;
845                 spec = ins_spec [ins->opcode];
846                 prev_dreg = -1;
847                 prev_sreg2 = -1;
848                 clob_dreg = -1;
849                 clob_reg = -1;
850                 dest_dreg = -1;
851                 dest_sreg1 = -1;
852                 dest_sreg2 = -1;
853                 dreg_mask = dreg_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
854                 sreg1_mask = sreg1_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
855                 sreg2_mask = sreg2_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
856
857                 DEBUG (g_print ("processing:"));
858                 DEBUG (print_ins (i, ins));
859
860                 ip = ins->cil_code;
861
862                 /*
863                  * FIXED REGS
864                  */
865                 dest_sreg1 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC1]);
866                 dest_sreg2 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC2]);
867                 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
868                 clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
869                 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
870
871                 /*
872                  * TRACK FP STACK
873                  */
874                 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
875                         if (dreg_is_fp (ins)) {
876                                 if (reginfof [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
877                                         GList *spill_node;
878                                         MonoInst *store;
879                                         spill_node = g_list_first (fspill_list);
880                                         g_assert (spill_node);
881
882                                         store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
883                                         insert_before_ins (ins, tmp, store);
884                                         fspill_list = g_list_remove (fspill_list, spill_node->data);
885                                         fspill--;
886                                 }
887                         }
888
889                         if (spec [MONO_INST_SRC1] == 'f') {
890                                 if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
891                                         MonoInst *load;
892                                         MonoInst *store = NULL;
893
894                                         if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
895                                                 GList *spill_node;
896                                                 spill_node = g_list_first (fspill_list);
897                                                 g_assert (spill_node);
898
899                                                 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);          
900                                                 fspill_list = g_list_remove (fspill_list, spill_node->data);
901                                         }
902
903                                         fspill++;
904                                         fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
905                                         load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
906                                         insert_before_ins (ins, tmp, load);
907                                         if (store) 
908                                                 insert_before_ins (load, tmp, store);
909                                 }
910                         }
911
912                         if (spec [MONO_INST_SRC2] == 'f') {
913                                 if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
914                                         MonoInst *load;
915                                         MonoInst *store = NULL;
916
917                                         if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
918                                                 GList *spill_node;
919
920                                                 spill_node = g_list_first (fspill_list);
921                                                 g_assert (spill_node);
922                                                 if (spec [MONO_INST_SRC1] == 'f' && (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
923                                                         spill_node = g_list_next (spill_node);
924         
925                                                 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
926                                                 fspill_list = g_list_remove (fspill_list, spill_node->data);
927                                         }
928                                 
929                                         fspill++;
930                                         fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
931                                         load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
932                                         insert_before_ins (ins, tmp, load);
933                                         if (store) 
934                                                 insert_before_ins (load, tmp, store);
935                                 }
936                         }
937                 }
938
939                 /*
940                  * TRACK FIXED SREG2
941                  */
942                 if (dest_sreg2 != -1) {
943                         if (rs->ifree_mask & (regmask (dest_sreg2))) {
944                                 if (is_global_ireg (ins->sreg2)) {
945                                         /* Argument already in hard reg, need to copy */
946                                         MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
947                                         insert_before_ins (ins, tmp, copy);
948                                 }
949                                 else {
950                                         DEBUG (g_print ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
951                                         assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
952                                 }
953                         } else {
954                                 int need_spill = TRUE;
955
956                                 dreg_mask &= ~ (regmask (dest_sreg2));
957                                 sreg1_mask &= ~ (regmask (dest_sreg2));
958
959                                 /* 
960                                  * First check if dreg is assigned to dest_sreg2, since we
961                                  * can't spill a dreg.
962                                  */
963                                 val = rs->iassign [ins->dreg];
964                                 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
965                                         /* 
966                                          * the destination register is already assigned to 
967                                          * dest_sreg2: we need to allocate another register for it 
968                                          * and then copy from this to dest_sreg2.
969                                          */
970                                         int new_dest;
971                                         new_dest = alloc_int_reg (cfg, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg]);
972                                         g_assert (new_dest >= 0);
973                                         DEBUG (g_print ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
974
975                                         prev_dreg = ins->dreg;
976                                         assign_ireg (cfg, rs, ins->dreg, new_dest);
977                                         clob_dreg = ins->dreg;
978                                         create_copy_ins (cfg, dest_sreg2, new_dest, ins, ip, FALSE);
979                                         need_spill = FALSE;
980                                 }
981
982                                 if (is_global_ireg (ins->sreg2)) {
983                                         MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
984                                         insert_before_ins (ins, tmp, copy);
985                                 }
986                                 else {
987                                         val = rs->iassign [ins->sreg2];
988                                         if (val == dest_sreg2) {
989                                                 /* sreg2 is already assigned to the correct register */
990                                                 need_spill = FALSE;
991                                         }
992                                         else if ((val >= 0) || (val < -1)) {
993                                                 /* FIXME: sreg2 already assigned to another register */
994                                                 g_assert_not_reached ();
995                                         }
996                                 }
997
998                                 if (need_spill) {
999                                         DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1000                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
1001                                         mono_regstate_free_int (rs, dest_sreg2);
1002                                 }
1003
1004                                 if (!is_global_ireg (ins->sreg2))
1005                                         /* force-set sreg2 */
1006                                         assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1007                         }
1008                         ins->sreg2 = dest_sreg2;
1009                 }
1010
1011                 /*
1012                  * TRACK DREG
1013                  */
1014                 fp = dreg_is_fp (ins);
1015                 if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
1016                         prev_dreg = ins->dreg;
1017
1018                 if (spec [MONO_INST_DEST] == 'b') {
1019                         /* 
1020                          * The dest reg is read by the instruction, not written, so
1021                          * avoid allocating sreg1/sreg2 to the same reg.
1022                          */
1023                         if (dest_sreg1 != -1)
1024                                 dreg_mask &= ~ (regmask (dest_sreg1));
1025                         if (dest_sreg2 != -1)
1026                                 dreg_mask &= ~ (regmask (dest_sreg2));
1027                 }
1028
1029                 /*
1030                  * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1031                  * various complex situations.
1032                  */
1033                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1034                         guint32 dreg2, dest_dreg2;
1035
1036                         g_assert (is_soft_reg (ins->dreg, fp));
1037
1038                         if (dest_dreg != -1) {
1039                                 if (rs->iassign [ins->dreg] != dest_dreg)
1040                                         free_up_ireg (cfg, tmp, ins, dest_dreg);
1041
1042                                 dreg2 = ins->dreg + 1;
1043                                 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
1044                                 if (dest_dreg2 != -1) {
1045                                         if (rs->iassign [dreg2] != dest_dreg2)
1046                                                 free_up_ireg (cfg, tmp, ins, dest_dreg2);
1047                                 }
1048                         }
1049                 }
1050
1051                 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
1052                         if (dest_dreg != -1)
1053                                 dreg_mask = (regmask (dest_dreg));
1054
1055                         val = rassign (cfg, ins->dreg, fp);
1056
1057                         if (val < 0) {
1058                                 int spill = 0;
1059                                 if (val < -1) {
1060                                         /* the register gets spilled after this inst */
1061                                         spill = -val -1;
1062                                 }
1063                                 val = alloc_reg (cfg, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg], fp);
1064                                 assign_reg (cfg, rs, ins->dreg, val, fp);
1065                                 if (spill)
1066                                         create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
1067                         }
1068                                 
1069                         DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
1070                         ins->dreg = val;
1071                 }
1072
1073                 /* Handle regpairs */
1074                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1075                         int reg2 = prev_dreg + 1;
1076
1077                         g_assert (!fp);
1078                         g_assert (prev_dreg > -1);
1079                         g_assert (!is_global_ireg (rs->iassign [prev_dreg]));
1080                         mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->iassign [prev_dreg]);
1081                         val = rs->iassign [reg2];
1082                         if (val < 0) {
1083                                 int spill = 0;
1084                                 if (val < -1) {
1085                                         /* the register gets spilled after this inst */
1086                                         spill = -val -1;
1087                                 }
1088                                 val = mono_regstate_alloc_int (rs, mask);
1089                                 if (val < 0)
1090                                         val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1091                                 if (spill)
1092                                         create_spilled_store (cfg, spill, val, reg2, ins, fp);
1093                         }
1094                         else {
1095                                 if (! (mask & (regmask (val)))) {
1096                                         val = mono_regstate_alloc_int (rs, mask);
1097                                         if (val < 0)
1098                                                 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1099
1100                                         /* Reallocate hreg to the correct register */
1101                                         create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
1102
1103                                         mono_regstate_free_int (rs, rs->iassign [reg2]);
1104                                 }
1105                         }                                       
1106
1107                         DEBUG (g_print ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1108                         assign_reg (cfg, rs, reg2, val, fp);
1109
1110                         dreg_high = val;
1111                         ins->unused = val;
1112
1113                         if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1114                                 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1115                                 mono_regstate_free_int (rs, val);
1116                         }
1117                 }
1118
1119                 if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && (fp ? reginfof : reginfo) [prev_dreg].born_in >= i) {
1120                         /* 
1121                          * In theory, we could free up the hreg even if the vreg is alive,
1122                          * but branches inside bblocks force us to assign the same hreg
1123                          * to a vreg every time it is encountered.
1124                          */
1125                         int dreg = rassign (cfg, prev_dreg, fp);
1126                         g_assert (dreg >= 0);
1127                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, (fp ? reginfof : reginfo) [prev_dreg].born_in));
1128                         if (fp)
1129                                 mono_regstate_free_float (rs, dreg);
1130                         else
1131                                 mono_regstate_free_int (rs, dreg);
1132                 }
1133
1134                 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1135                         /* this instruction only outputs to dest_dreg, need to copy */
1136                         create_copy_ins (cfg, ins->dreg, dest_dreg, ins, ip, fp);
1137                         ins->dreg = dest_dreg;
1138
1139                         if (fp) {
1140                                 if (rs->fsymbolic [dest_dreg] >= MONO_MAX_FREGS)
1141                                         free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1142                         }
1143                         else {
1144                                 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1145                                         free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1146                         }
1147                 }
1148
1149                 if (spec [MONO_INST_DEST] == 'b') {
1150                         /* 
1151                          * The dest reg is read by the instruction, not written, so
1152                          * avoid allocating sreg1/sreg2 to the same reg.
1153                          */
1154                         sreg1_mask &= ~ (regmask (ins->dreg));
1155                         sreg2_mask &= ~ (regmask (ins->dreg));
1156                 }
1157
1158                 /*
1159                  * TRACK CLOBBERING
1160                  */
1161                 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1162                         DEBUG (g_print ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1163                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
1164                         mono_regstate_free_int (rs, clob_reg);
1165                 }
1166
1167                 if (spec [MONO_INST_CLOB] == 'c') {
1168                         int j, s, dreg, dreg2;
1169                         guint64 clob_mask;
1170
1171                         clob_mask = MONO_ARCH_CALLEE_REGS;
1172
1173                         /*
1174                          * Need to avoid spilling the dreg since the dreg is not really
1175                          * clobbered by the call.
1176                          */
1177                         if ((prev_dreg != -1) && !dreg_is_fp (ins))
1178                                 dreg = rassign (cfg, prev_dreg, dreg_is_fp (ins));
1179                         else
1180                                 dreg = -1;
1181
1182                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
1183                                 dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (ins));
1184                         else
1185                                 dreg2 = -1;
1186
1187                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
1188                                 s = regmask (j);
1189                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
1190                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
1191                                         mono_regstate_free_int (rs, j);
1192                                 }
1193                         }
1194
1195                         if (!use_fpstack) {
1196                                 clob_mask = MONO_ARCH_CALLEE_FREGS;
1197                                 if ((prev_dreg != -1) && dreg_is_fp (ins))
1198                                         dreg = rassign (cfg, prev_dreg, dreg_is_fp (ins));
1199                                 else
1200                                         dreg = -1;
1201
1202                                 for (j = 0; j < MONO_MAX_FREGS; ++j) {
1203                                         s = regmask (j);
1204                                         if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
1205                                                 get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
1206                                                 mono_regstate_free_float (rs, j);
1207                                         }
1208                                 }
1209                         }
1210                 }
1211
1212                 /*
1213                  * TRACK ARGUMENT REGS
1214                  */
1215                 if (spec [MONO_INST_CLOB] == 'c') {
1216                         MonoCallInst *call = (MonoCallInst*)ins;
1217                         GSList *list;
1218
1219                         /* 
1220                          * This needs to be done before assigning sreg1, so sreg1 will
1221                          * not be assigned one of the argument regs.
1222                          */
1223
1224                         /* 
1225                          * Assign all registers in call->out_reg_args to the proper 
1226                          * argument registers.
1227                          */
1228
1229                         list = call->out_ireg_args;
1230                         if (list) {
1231                                 while (list) {
1232                                         guint32 regpair;
1233                                         int reg, hreg;
1234
1235                                         regpair = (guint32)(gssize)(list->data);
1236                                         hreg = regpair >> 24;
1237                                         reg = regpair & 0xffffff;
1238
1239                                         assign_reg (cfg, rs, reg, hreg, FALSE);
1240
1241                                         sreg1_mask &= ~(regmask (hreg));
1242
1243                                         DEBUG (g_print ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1244
1245                                         list = g_slist_next (list);
1246                                 }
1247                                 g_slist_free (call->out_ireg_args);
1248                         }
1249
1250                         list = call->out_freg_args;
1251                         if (list && !use_fpstack) {
1252                                 while (list) {
1253                                         guint32 regpair;
1254                                         int reg, hreg;
1255
1256                                         regpair = (guint32)(gssize)(list->data);
1257                                         hreg = regpair >> 24;
1258                                         reg = regpair & 0xffffff;
1259
1260                                         assign_reg (cfg, rs, reg, hreg, TRUE);
1261
1262                                         DEBUG (g_print ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
1263
1264                                         list = g_slist_next (list);
1265                                 }
1266                         }
1267                         if (call->out_freg_args)
1268                                 g_slist_free (call->out_freg_args);
1269                 }
1270
1271                 /*
1272                  * TRACK SREG1
1273                  */
1274                 fp = sreg1_is_fp (ins);
1275                 if ((!fp || (fp && !use_fpstack))) {
1276                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
1277                                 g_assert (is_soft_reg (ins->sreg1, fp));
1278
1279                                 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1280                                 if (dest_sreg1 != -1)
1281                                         g_assert (dest_sreg1 == ins->dreg);
1282                                 val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
1283                                 g_assert (val >= 0);
1284                                 assign_reg (cfg, rs, ins->sreg1, val, fp);
1285
1286                                 DEBUG (g_print ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1287
1288                                 g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
1289                                 val = mono_regstate_alloc_int (rs, regmask (dreg_high));
1290                                 g_assert (val >= 0);
1291                                 assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
1292
1293                                 DEBUG (g_print ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
1294
1295                                 /* Skip rest of this section */
1296                                 dest_sreg1 = -1;
1297                         }
1298
1299                         if (dest_sreg1 != -1) {
1300                                 sreg1_mask = regmask (dest_sreg1);
1301
1302                                 if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
1303                                         DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1304                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
1305                                         mono_regstate_free_int (rs, dest_sreg1);
1306                                 }
1307                                 if (is_global_ireg (ins->sreg1)) {
1308                                         /* The argument is already in a hard reg, need to copy */
1309                                         MonoInst *copy = create_copy_ins (cfg, dest_sreg1, ins->sreg1, NULL, ip, FALSE);
1310                                         insert_before_ins (ins, tmp, copy);
1311                                         ins->sreg1 = dest_sreg1;
1312                                 }
1313                         }
1314
1315                         if (is_soft_reg (ins->sreg1, fp)) {
1316                                 val = rassign (cfg, ins->sreg1, fp);
1317                                 prev_sreg1 = ins->sreg1;
1318                                 if (val < 0) {
1319                                         int spill = 0;
1320                                         if (val < -1) {
1321                                                 /* the register gets spilled after this inst */
1322                                                 spill = -val -1;
1323                                         }
1324
1325                                         if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (!is_global_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
1326                                                 /* 
1327                                                  * Allocate the same hreg to sreg1 as well so the 
1328                                                  * peephole can get rid of the move.
1329                                                  */
1330                                                 sreg1_mask = regmask (ins->dreg);
1331                                         }
1332
1333                                         val = alloc_reg (cfg, tmp, ins, sreg1_mask, ins->sreg1, &reginfo [ins->sreg1], fp);
1334                                         assign_reg (cfg, rs, ins->sreg1, val, fp);
1335                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1336
1337                                         if (spill) {
1338                                                 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
1339                                                 /*
1340                                                  * Need to insert before the instruction since it can
1341                                                  * overwrite sreg1.
1342                                                  */
1343                                                 insert_before_ins (ins, tmp, store);
1344                                         }
1345                                 }
1346                                 else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1347                                         g_assert_not_reached ();
1348                                 }
1349                                 
1350                                 ins->sreg1 = val;
1351                         }
1352                         else {
1353                                 prev_sreg1 = -1;
1354                         }
1355                         sreg2_mask &= ~(regmask (ins->sreg1));
1356                 }
1357
1358                 /* Handle the case when sreg1 is a regpair but dreg is not */
1359                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1]) && (spec [MONO_INST_CLOB] != '1')) {
1360                         int reg2 = prev_sreg1 + 1;
1361
1362                         g_assert (!fp);
1363                         g_assert (prev_sreg1 > -1);
1364                         g_assert (!is_global_ireg (rs->iassign [prev_sreg1]));
1365                         mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->iassign [prev_sreg1]);
1366                         val = rs->iassign [reg2];
1367                         if (val < 0) {
1368                                 int spill = 0;
1369                                 if (val < -1) {
1370                                         /* the register gets spilled after this inst */
1371                                         spill = -val -1;
1372                                 }
1373                                 val = mono_regstate_alloc_int (rs, mask);
1374                                 if (val < 0)
1375                                         val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1376                                 if (spill)
1377                                         g_assert_not_reached ();
1378                         }
1379                         else {
1380                                 if (! (mask & (regmask (val)))) {
1381                                         /* The vreg is already allocated to a wrong hreg */
1382                                         /* FIXME: */
1383                                         g_assert_not_reached ();
1384 #if 0
1385                                         val = mono_regstate_alloc_int (rs, mask);
1386                                         if (val < 0)
1387                                                 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1388
1389                                         /* Reallocate hreg to the correct register */
1390                                         create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
1391
1392                                         mono_regstate_free_int (rs, rs->iassign [reg2]);
1393 #endif
1394                                 }
1395                         }                                       
1396
1397                         sreg1_high = val;
1398                         DEBUG (g_print ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1399                         assign_reg (cfg, rs, reg2, val, fp);
1400                 }
1401
1402                 /* Handle dreg==sreg1 */
1403                 if (((dreg_is_fp (ins) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1404                         MonoInst *sreg2_copy = NULL;
1405                         MonoInst *copy;
1406                         gboolean fp = (spec [MONO_INST_SRC1] == 'f');
1407
1408                         if (ins->dreg == ins->sreg2) {
1409                                 /* 
1410                                  * copying sreg1 to dreg could clobber sreg2, so allocate a new
1411                                  * register for it.
1412                                  */
1413                                 int reg2 = alloc_reg (cfg, tmp, ins, dreg_mask, ins->sreg2, NULL, fp);
1414
1415                                 DEBUG (g_print ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
1416                                 sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
1417                                 prev_sreg2 = ins->sreg2 = reg2;
1418
1419                                 if (fp)
1420                                         mono_regstate_free_float (rs, reg2);
1421                                 else
1422                                         mono_regstate_free_int (rs, reg2);
1423                         }
1424
1425                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
1426                                 /* Copying sreg1_high to dreg could also clobber sreg2 */
1427                                 if (rs->iassign [prev_sreg1 + 1] == ins->sreg2)
1428                                         /* FIXME: */
1429                                         g_assert_not_reached ();
1430
1431                                 /* 
1432                                  * sreg1 and dest are already allocated to the same regpair by the
1433                                  * SREG1 allocation code.
1434                                  */
1435                                 g_assert (ins->sreg1 == ins->dreg);
1436                                 g_assert (dreg_high == sreg1_high);
1437                         }
1438
1439                         DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
1440                         copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
1441                         insert_before_ins (ins, tmp, copy);
1442
1443                         if (sreg2_copy)
1444                                 insert_before_ins (copy, tmp, sreg2_copy);
1445
1446                         /*
1447                          * Need to prevent sreg2 to be allocated to sreg1, since that
1448                          * would screw up the previous copy.
1449                          */
1450                         sreg2_mask &= ~ (regmask (ins->sreg1));
1451                         /* we set sreg1 to dest as well */
1452                         prev_sreg1 = ins->sreg1 = ins->dreg;
1453                         sreg2_mask &= ~ (regmask (ins->dreg));
1454                 }
1455
1456                 /*
1457                  * TRACK SREG2
1458                  */
1459                 fp = sreg2_is_fp (ins);
1460                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
1461                         g_assert_not_reached ();
1462                 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
1463                         val = rassign (cfg, ins->sreg2, fp);
1464
1465                         if (val < 0) {
1466                                 int spill = 0;
1467                                 if (val < -1) {
1468                                         /* the register gets spilled after this inst */
1469                                         spill = -val -1;
1470                                 }
1471                                 val = alloc_reg (cfg, tmp, ins, sreg2_mask, ins->sreg2, &reginfo [ins->sreg2], fp);
1472                                 assign_reg (cfg, rs, ins->sreg2, val, fp);
1473                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
1474                                 if (spill)
1475                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins, fp);
1476                         }
1477                         ins->sreg2 = val;
1478                 }
1479                 else {
1480                         prev_sreg2 = -1;
1481                 }
1482
1483                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1484                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1485                         mono_regstate_free_int (rs, ins->sreg1);
1486                 }
1487                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1488                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1489                         mono_regstate_free_int (rs, ins->sreg2);
1490                 }*/
1491         
1492                 DEBUG (print_ins (i, ins));
1493                 /* this may result from a insert_before call */
1494                 if (!tmp->next)
1495                         bb->code = tmp->data;
1496                 tmp = tmp->next;
1497         }
1498
1499         g_free (reginfo);
1500         g_free (reginfof);
1501         g_list_free (fspill_list);
1502 }