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