93938bebd868c658b44cc1ea7db30bdc6e562e30
[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) MINI_DEBUG(cfg->verbose_level, 2, a;)
23
24 #define use_fpstack MONO_ARCH_USE_FPSTACK
25
26 static inline GSList*
27 g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
28 {
29         GSList *new_list;
30         GSList *last;
31         
32         new_list = mono_mempool_alloc (mp, sizeof (GSList));
33         new_list->data = data;
34         new_list->next = NULL;
35         
36         if (list) {
37                 last = list;
38                 while (last->next)
39                         last = last->next;
40                 last->next = new_list;
41                 
42                 return list;
43         } else
44                 return new_list;
45 }
46
47 /**
48  * Duplicated here from regalloc.c so they can be inlined
49  * FIXME: Remove the old one after the new JIT is done
50  */
51
52 static inline void
53 mono_regstate2_reset (MonoRegState *rs) {
54         rs->next_vreg = MONO_MAX_IREGS;
55 }
56
57 static inline MonoRegState*
58 mono_regstate2_new (void)
59 {
60         MonoRegState* rs = g_new0 (MonoRegState, 1);
61
62         mono_regstate2_reset (rs);
63
64         return rs;
65 }
66
67 static inline void
68 mono_regstate2_free (MonoRegState *rs) {
69         g_free (rs->vassign);
70         g_free (rs);
71 }
72
73 static inline void
74 mono_regstate_assign (MonoRegState *rs) {
75         if (rs->next_vreg > rs->vassign_size) {
76                 g_free (rs->vassign);
77                 rs->vassign_size = MAX (rs->next_vreg, 256);
78                 rs->vassign = g_malloc (rs->vassign_size * sizeof (int));
79         }
80
81         memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
82         memset (rs->vassign, -1, sizeof (rs->vassign [0]) * rs->next_vreg);
83
84         memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
85 }
86
87 static inline int
88 mono_regstate_alloc_int (MonoRegState *rs, regmask_t allow)
89 {
90         regmask_t mask = allow & rs->ifree_mask;
91
92 #if defined(__x86_64__) && defined(__GNUC__)
93  {
94         guint64 i;
95
96         if (mask == 0)
97                 return -1;
98
99         __asm__("bsfq %1,%0\n\t"
100                         : "=r" (i) : "rm" (mask));
101
102         rs->ifree_mask &= ~ ((regmask_t)1 << i);
103         return i;
104  }
105 #else
106         int i;
107
108         for (i = 0; i < MONO_MAX_IREGS; ++i) {
109                 if (mask & ((regmask_t)1 << i)) {
110                         rs->ifree_mask &= ~ ((regmask_t)1 << i);
111                         return i;
112                 }
113         }
114         return -1;
115 #endif
116 }
117
118 static inline void
119 mono_regstate_free_int (MonoRegState *rs, int reg)
120 {
121         if (reg >= 0) {
122                 rs->ifree_mask |= (regmask_t)1 << reg;
123                 rs->isymbolic [reg] = 0;
124         }
125 }
126
127 static inline int
128 mono_regstate_alloc_float (MonoRegState *rs, regmask_t allow)
129 {
130         int i;
131         regmask_t mask = allow & rs->ffree_mask;
132         for (i = 0; i < MONO_MAX_FREGS; ++i) {
133                 if (mask & ((regmask_t)1 << i)) {
134                         rs->ffree_mask &= ~ ((regmask_t)1 << i);
135                         return i;
136                 }
137         }
138         return -1;
139 }
140
141 static inline void
142 mono_regstate_free_float (MonoRegState *rs, int reg)
143 {
144         if (reg >= 0) {
145                 rs->ffree_mask |= (regmask_t)1 << reg;
146                 rs->fsymbolic [reg] = 0;
147         }
148 }
149
150 static inline int
151 mono_regstate2_next_long (MonoRegState *rs)
152 {
153         int rval = rs->next_vreg;
154
155         rs->next_vreg += 2;
156
157         return rval;
158 }
159
160 const char*
161 mono_regname_full (int reg, gboolean fp)
162 {
163         if (fp)
164                 return mono_arch_fregname (reg);
165         else
166                 return mono_arch_regname (reg);
167 }
168
169 void
170 mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, gboolean fp)
171 {
172         guint32 regpair;
173
174         regpair = (((guint32)hreg) << 24) + vreg;
175         if (fp) {
176                 g_assert (vreg >= MONO_MAX_FREGS);
177                 g_assert (hreg < MONO_MAX_FREGS);
178                 call->used_fregs |= 1 << hreg;
179                 call->out_freg_args = g_slist_append_mempool (cfg->mempool, call->out_freg_args, (gpointer)(gssize)(regpair));
180         } else {
181                 g_assert (vreg >= MONO_MAX_IREGS);
182                 g_assert (hreg < MONO_MAX_IREGS);
183                 call->used_iregs |= 1 << hreg;
184                 call->out_ireg_args = g_slist_append_mempool (cfg->mempool, call->out_ireg_args, (gpointer)(gssize)(regpair));
185         }
186 }
187
188 static void
189 resize_spill_info (MonoCompile *cfg, gboolean fp)
190 {
191         MonoSpillInfo *orig_info = fp ? cfg->spill_info_float : cfg->spill_info;
192         int orig_len = fp ? cfg->spill_info_float_len : cfg->spill_info_len;
193         int new_len = orig_len ? orig_len * 2 : 16;
194         MonoSpillInfo *new_info;
195         int i;
196
197         new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
198         if (orig_info)
199                 memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
200         for (i = orig_len; i < new_len; ++i)
201                 new_info [i].offset = -1;
202
203         if (!fp) {
204                 cfg->spill_info = new_info;
205                 cfg->spill_info_len = new_len;
206         } else {
207                 cfg->spill_info_float = new_info;
208                 cfg->spill_info_float_len = new_len;
209         }
210 }
211
212 /*
213  * returns the offset used by spillvar. It allocates a new
214  * spill variable if necessary. 
215  */
216 static inline int
217 mono_spillvar_offset_int (MonoCompile *cfg, int spillvar)
218 {
219         MonoSpillInfo *info;
220
221 #if defined (__mips__)
222         g_assert_not_reached();
223 #endif
224         if (G_UNLIKELY (spillvar >= cfg->spill_info_len)) {
225                 resize_spill_info (cfg, FALSE);
226                 g_assert (spillvar < cfg->spill_info_len);
227         }
228
229         info = &cfg->spill_info [spillvar];
230         if (info->offset == -1) {
231                 cfg->stack_offset += sizeof (gpointer) - 1;
232                 cfg->stack_offset &= ~(sizeof (gpointer) - 1);
233
234                 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
235                         info->offset = cfg->stack_offset;
236                         cfg->stack_offset += sizeof (gpointer);
237                 } else {
238                         cfg->stack_offset += sizeof (gpointer);
239                         info->offset = - cfg->stack_offset;
240                 }
241         }
242
243         return info->offset;
244 }
245
246 /*
247  * returns the offset used by spillvar. It allocates a new
248  * spill float variable if necessary. 
249  * (same as mono_spillvar_offset but for float)
250  */
251 static inline int
252 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
253 {
254         MonoSpillInfo *info;
255
256 #if defined (__mips__)
257         g_assert_not_reached();
258 #endif
259         if (G_UNLIKELY (spillvar >= cfg->spill_info_float_len)) {
260                 resize_spill_info (cfg, TRUE);
261                 g_assert (spillvar < cfg->spill_info_float_len);
262         }
263
264         info = &cfg->spill_info_float [spillvar];
265         if (info->offset == -1) {
266                 cfg->stack_offset += sizeof (double) - 1;
267                 cfg->stack_offset &= ~(sizeof (double) - 1);
268
269                 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
270                         info->offset = cfg->stack_offset;
271                         cfg->stack_offset += sizeof (double);
272                 } else {
273                         cfg->stack_offset += sizeof (double);
274                         info->offset = - cfg->stack_offset;
275                 }
276         }
277
278         return info->offset;
279 }
280
281 static inline int
282 mono_spillvar_offset (MonoCompile *cfg, int spillvar, gboolean fp)
283 {
284         if (fp)
285                 return mono_spillvar_offset_float (cfg, spillvar);
286         else
287                 return mono_spillvar_offset_int (cfg, spillvar);
288 }
289
290 #if MONO_ARCH_USE_FPSTACK
291
292 /*
293  * Creates a store for spilled floating point items
294  */
295 static MonoInst*
296 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
297 {
298         MonoInst *store;
299         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
300         store->sreg1 = reg;
301         store->inst_destbasereg = cfg->frame_reg;
302         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
303
304         DEBUG (printf ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
305         return store;
306 }
307
308 /*
309  * Creates a load for spilled floating point items 
310  */
311 static MonoInst*
312 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
313 {
314         MonoInst *load;
315         MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
316         load->dreg = reg;
317         load->inst_basereg = cfg->frame_reg;
318         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
319
320         DEBUG (printf ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
321         return load;
322 }
323
324 #endif /* MONO_ARCH_USE_FPSTACK */
325
326 #define regmask(reg) (((regmask_t)1) << (reg))
327
328 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
329 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
330 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
331 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
332 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
333 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
334 #define ireg_is_freeable(r) is_local_ireg ((r))
335 #define freg_is_freeable(r) is_hard_freg ((r))
336
337 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
338 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
339 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
340 #define rassign(cfg,reg,fp) ((cfg)->rs->vassign [(reg)])
341
342 #ifdef MONO_ARCH_INST_IS_FLOAT
343 #define dreg_is_fp(spec)  (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
344 #define sreg1_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC1]))
345 #define sreg2_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC2]))
346 #else
347 #define sreg1_is_fp(spec) (spec [MONO_INST_SRC1] == 'f')
348 #define sreg2_is_fp(spec) (spec [MONO_INST_SRC2] == 'f')
349 #define dreg_is_fp(spec)  (spec [MONO_INST_DEST] == 'f')
350 #endif
351
352 #define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_get_spec ((ins)->opcode)))
353 #define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_get_spec ((ins)->opcode)))
354 #define dreg_is_fp_ins(ins)  (dreg_is_fp (ins_get_spec ((ins)->opcode)))
355
356 #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)
357
358 #ifdef MONO_ARCH_IS_GLOBAL_IREG
359 #undef is_global_ireg
360 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
361 #endif
362
363 typedef struct {
364         int born_in;
365         int killed_in;
366         /* Not (yet) used */
367         //int last_use;
368         //int prev_use;
369 #if MONO_ARCH_USE_FPSTACK
370         int flags;              /* used to track fp spill/load */
371 #endif
372         regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
373 } RegTrack;
374
375 #ifndef DISABLE_LOGGING
376 void
377 mono_print_ins (int i, MonoInst *ins)
378 {
379         const char *spec = ins_get_spec (ins->opcode);
380         printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
381         if (!spec)
382                 g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
383
384         if (spec [MONO_INST_DEST]) {
385                 gboolean fp = dreg_is_fp_ins (ins);
386                 if (is_soft_reg (ins->dreg, fp)) {
387                         if (spec [MONO_INST_DEST] == 'b') {
388                                 if (ins->inst_offset == 0)
389                                         printf (" [R%d] <-", ins->dreg);
390                                 else
391                                         printf (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
392                         }
393                         else
394                                 printf (" R%d <-", ins->dreg);
395                 } else if (spec [MONO_INST_DEST] == 'b') {
396                         if (ins->inst_offset == 0)
397                                 printf (" [%s] <-", mono_arch_regname (ins->dreg));
398                         else
399                                 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
400                 } else
401                         printf (" %s <-", mono_regname_full (ins->dreg, fp));
402         }
403         if (spec [MONO_INST_SRC1]) {
404                 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
405                 if (is_soft_reg (ins->sreg1, fp))
406                         printf (" R%d", ins->sreg1);
407                 else if (spec [MONO_INST_SRC1] == 'b')
408                         printf (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
409                 else
410                         printf (" %s", mono_regname_full (ins->sreg1, fp));
411         }
412         if (spec [MONO_INST_SRC2]) {
413                 gboolean fp = (spec [MONO_INST_SRC2] == 'f');
414                 if (is_soft_reg (ins->sreg2, fp))
415                         printf (" R%d", ins->sreg2);
416                 else
417                         printf (" %s", mono_regname_full (ins->sreg2, fp));
418         }
419         if (spec [MONO_INST_CLOB])
420                 printf (" clobbers: %c", spec [MONO_INST_CLOB]);
421         printf ("\n");
422 }
423
424 static void
425 print_regtrack (RegTrack *t, int num)
426 {
427         int i;
428         char buf [32];
429         const char *r;
430         
431         for (i = 0; i < num; ++i) {
432                 if (!t [i].born_in)
433                         continue;
434                 if (i >= MONO_MAX_IREGS) {
435                         g_snprintf (buf, sizeof(buf), "R%d", i);
436                         r = buf;
437                 } else
438                         r = mono_arch_regname (i);
439                 printf ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].killed_in);
440         }
441 }
442 #endif /* DISABLE_LOGGING */
443
444 typedef struct InstList InstList;
445
446 struct InstList {
447         InstList *prev;
448         InstList *next;
449         MonoInst *data;
450 };
451
452 static inline InstList*
453 inst_list_prepend (guint8 *mem, InstList *list, MonoInst *data)
454 {
455         InstList *item = (InstList*)(gpointer)mem;
456         item->data = data;
457         item->prev = NULL;
458         item->next = list;
459         if (list)
460                 list->prev = item;
461         return item;
462 }
463
464 static inline void
465 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
466 {
467         MonoInst *prev;
468
469         /*
470          * If this function is called multiple times, the new instructions are inserted
471          * in the proper order.
472          */
473
474         if (item->next) {
475                 prev = item->next->data;
476
477                 while (prev->next != ins)
478                         prev = prev->next;
479                 to_insert->next = ins;
480                 prev->next = to_insert;
481         } else {
482                 to_insert->next = ins;
483         }
484
485         /*
486          * insert_after_ins insert the new instruction before item->data, so
487          * we have to modify it to point to the first of the prepended instructions.
488          */
489         if (item->data == ins)
490                 item->data = to_insert; 
491 }
492
493 static inline void
494 insert_after_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
495 {
496         if (item->prev) {
497                 while (ins->next != item->prev->data)
498                         ins = ins->next;
499         }
500         to_insert->next = ins->next;
501         ins->next = to_insert;
502 }
503
504 /*
505  * Force the spilling of the variable in the symbolic register 'reg'.
506  */
507 static int
508 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg, gboolean fp)
509 {
510         MonoInst *load;
511         int i, sel, spill;
512         int *assign, *symbolic;
513
514         assign = cfg->rs->vassign;
515         if (fp)
516                 symbolic = cfg->rs->fsymbolic;
517         else
518                 symbolic = cfg->rs->isymbolic;
519         
520         sel = cfg->rs->vassign [reg];
521         /*i = cfg->rs->isymbolic [sel];
522         g_assert (i == reg);*/
523         i = reg;
524         spill = ++cfg->spill_count;
525         assign [i] = -spill - 1;
526         if (fp)
527                 mono_regstate_free_float (cfg->rs, sel);
528         else
529                 mono_regstate_free_int (cfg->rs, sel);
530         /* we need to create a spill var and insert a load to sel after the current instruction */
531         if (fp)
532                 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
533         else
534                 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
535         load->dreg = sel;
536         load->inst_basereg = cfg->frame_reg;
537         load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
538         insert_after_ins (ins, item, load);
539         DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
540         if (fp)
541                 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
542         else
543                 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
544         g_assert (i == sel);
545
546         return sel;
547 }
548
549 /* This isn't defined on older glib versions and on some platforms */
550 #ifndef G_GUINT64_FORMAT
551 #define G_GUINT64_FORMAT "ul"
552 #endif
553
554 static int
555 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_t regmask, int reg, gboolean fp)
556 {
557         MonoInst *load;
558         int i, sel, spill;
559         int *assign, *symbolic;
560
561         assign = cfg->rs->vassign;
562         if (fp)
563                 symbolic = cfg->rs->fsymbolic;
564         else
565                 symbolic = cfg->rs->isymbolic;
566
567         DEBUG (printf ("\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));
568         /* exclude the registers in the current instruction */
569         if ((sreg1_is_fp_ins (ins) == fp) && (reg != ins->sreg1) && (reg_is_freeable (ins->sreg1, fp) || (is_soft_reg (ins->sreg1, fp) && rassign (cfg, ins->sreg1, fp) >= 0))) {
570                 if (is_soft_reg (ins->sreg1, fp))
571                         regmask &= ~ (regmask (rassign (cfg, ins->sreg1, fp)));
572                 else
573                         regmask &= ~ (regmask (ins->sreg1));
574                 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
575         }
576         if ((sreg2_is_fp_ins (ins) == fp) && (reg != ins->sreg2) && (reg_is_freeable (ins->sreg2, fp) || (is_soft_reg (ins->sreg2, fp) && rassign (cfg, ins->sreg2, fp) >= 0))) {
577                 if (is_soft_reg (ins->sreg2, fp))
578                         regmask &= ~ (regmask (rassign (cfg, ins->sreg2, fp)));
579                 else
580                         regmask &= ~ (regmask (ins->sreg2));
581                 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
582         }
583         if ((dreg_is_fp_ins (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
584                 regmask &= ~ (regmask (ins->dreg));
585                 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
586         }
587
588         DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
589         g_assert (regmask); /* need at least a register we can free */
590         sel = -1;
591         /* we should track prev_use and spill the register that's farther */
592         if (fp) {
593                 for (i = 0; i < MONO_MAX_FREGS; ++i) {
594                         if (regmask & (regmask (i))) {
595                                 sel = i;
596                                 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
597                                 break;
598                         }
599                 }
600
601                 i = cfg->rs->fsymbolic [sel];
602                 spill = ++cfg->spill_count;
603                 cfg->rs->vassign [i] = -spill - 1;
604                 mono_regstate_free_float (cfg->rs, sel);
605         }
606         else {
607                 for (i = 0; i < MONO_MAX_IREGS; ++i) {
608                         if (regmask & (regmask (i))) {
609                                 sel = i;
610                                 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
611                                 break;
612                         }
613                 }
614
615                 i = cfg->rs->isymbolic [sel];
616                 spill = ++cfg->spill_count;
617                 cfg->rs->vassign [i] = -spill - 1;
618                 mono_regstate_free_int (cfg->rs, sel);
619         }
620
621         /* we need to create a spill var and insert a load to sel after the current instruction */
622         MONO_INST_NEW (cfg, load, fp ? OP_LOADR8_MEMBASE : OP_LOAD_MEMBASE);
623         load->dreg = sel;
624         load->inst_basereg = cfg->frame_reg;
625         load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
626         insert_after_ins (ins, item, load);
627         DEBUG (printf ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
628         if (fp)
629                 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
630         else
631                 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
632         g_assert (i == sel);
633         
634         return sel;
635 }
636
637 static void
638 free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
639 {
640         if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
641                 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
642                 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
643                 mono_regstate_free_int (cfg->rs, hreg);
644         }
645 }
646
647 static void
648 free_up_reg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg, gboolean fp)
649 {
650         if (fp) {
651                 if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
652                         DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
653                         get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
654                         mono_regstate_free_float (cfg->rs, hreg);
655                 }
656         }
657         else {
658                 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
659                         DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
660                         get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
661                         mono_regstate_free_int (cfg->rs, hreg);
662                 }
663         }
664 }
665
666 static MonoInst*
667 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins, const unsigned char *ip, gboolean fp)
668 {
669         MonoInst *copy;
670
671         if (fp)
672                 MONO_INST_NEW (cfg, copy, OP_FMOVE);
673         else
674                 MONO_INST_NEW (cfg, copy, OP_MOVE);
675
676         copy->dreg = dest;
677         copy->sreg1 = src;
678         copy->cil_code = ip;
679         if (ins) {
680                 copy->next = ins->next;
681                 copy->cil_code = ins->cil_code;
682                 ins->next = copy;
683         }
684         DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
685         return copy;
686 }
687
688 static MonoInst*
689 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins, gboolean fp)
690 {
691         MonoInst *store;
692         MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
693         store->sreg1 = reg;
694         store->inst_destbasereg = cfg->frame_reg;
695         store->inst_offset = mono_spillvar_offset (cfg, spill, fp);
696         if (ins) {
697                 store->next = ins->next;
698                 ins->next = store;
699         }
700         DEBUG (printf ("\tSPILLED STORE (%d at 0x%08lx(%%ebp)) R%d (from %s)\n", spill, (long)store->inst_offset, prev_reg, mono_regname_full (reg, fp)));
701         return store;
702 }
703
704 /* flags used in reginfo->flags */
705 enum {
706         MONO_FP_NEEDS_LOAD_SPILL        = regmask (0),
707         MONO_FP_NEEDS_SPILL                     = regmask (1),
708         MONO_FP_NEEDS_LOAD                      = regmask (2)
709 };
710
711 static inline int
712 alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
713 {
714         int val;
715
716         if (info && info->preferred_mask) {
717                 val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
718                 if (val >= 0) {
719                         DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
720                         return val;
721                 }
722         }
723
724         val = mono_regstate_alloc_int (cfg->rs, dest_mask);
725         if (val < 0)
726                 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
727
728         return val;
729 }
730
731 static inline int
732 alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg)
733 {
734         int val;
735
736         val = mono_regstate_alloc_float (cfg->rs, dest_mask);
737
738         if (val < 0) {
739                 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
740         }
741
742         return val;
743 }
744
745 static inline int
746 alloc_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
747 {
748         if (fp)
749                 return alloc_float_reg (cfg, tmp, ins, dest_mask, sym_reg);
750         else
751                 return alloc_int_reg (cfg, tmp, ins, dest_mask, sym_reg, info);
752 }
753
754 static inline void
755 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
756 {
757         if (fp) {
758                 g_assert (reg >= MONO_MAX_FREGS);
759                 g_assert (hreg < MONO_MAX_FREGS);
760                 g_assert (! is_global_freg (hreg));
761
762                 rs->vassign [reg] = hreg;
763                 rs->fsymbolic [hreg] = reg;
764                 rs->ffree_mask &= ~ (regmask (hreg));
765         }
766         else {
767                 g_assert (reg >= MONO_MAX_IREGS);
768                 g_assert (hreg < MONO_MAX_IREGS);
769                 g_assert (! is_global_ireg (hreg));
770
771                 rs->vassign [reg] = hreg;
772                 rs->isymbolic [hreg] = reg;
773                 rs->ifree_mask &= ~ (regmask (hreg));
774         }
775 }
776
777 static inline void
778 assign_ireg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg)
779 {
780         assign_reg (cfg, rs, reg, hreg, FALSE);
781 }
782
783 /*
784  * Local register allocation.
785  * We first scan the list of instructions and we save the liveness info of
786  * each register (when the register is first used, when it's value is set etc.).
787  * We also reverse the list of instructions (in the InstList list) because assigning
788  * registers backwards allows for more tricks to be used.
789  */
790 void
791 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
792 {
793         MonoInst *ins;
794         MonoRegState *rs = cfg->rs;
795         int i, val, fpcount, ins_count;
796         RegTrack *reginfo;
797         InstList *tmp, *reversed = NULL;
798         const char *spec;
799         GList *fspill_list = NULL;
800         gboolean fp;
801         int fspill = 0;
802         guint8 *inst_list, *mem;
803 #if MONO_ARCH_USE_FPSTACK
804         gboolean need_fpstack = use_fpstack;
805 #endif
806
807         if (!bb->code)
808                 return;
809
810         rs->next_vreg = bb->max_vreg;
811         mono_regstate_assign (rs);
812
813         rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
814         rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
815
816         if (use_fpstack)
817                 rs->ffree_mask = 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE));
818
819         ins = bb->code;
820
821         /*if (cfg->opt & MONO_OPT_COPYPROP)
822                 local_copy_prop (cfg, ins);*/
823
824         if (cfg->reginfo && cfg->reginfo_len < rs->next_vreg) {
825                 cfg->reginfo = NULL;
826         }
827         reginfo = cfg->reginfo;
828         if (!reginfo) {
829                 cfg->reginfo_len = MAX (256, rs->next_vreg * 2);
830                 reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
831         } 
832         else
833                 g_assert (cfg->reginfo_len >= rs->next_vreg);
834
835         memset (reginfo, 0, rs->next_vreg * sizeof (RegTrack));
836
837         ins_count = 0;
838         for (ins = bb->code; ins; ins = ins->next) {
839                 ins_count ++;
840         }
841
842         if (cfg->reverse_inst_list && (cfg->reverse_inst_list_len < ins_count)) {
843                 cfg->reverse_inst_list = NULL;
844         }
845
846         inst_list = cfg->reverse_inst_list;
847         if (!inst_list) {
848                 cfg->reverse_inst_list_len = MAX (ins_count, 1024);
849                 inst_list = cfg->reverse_inst_list = mono_mempool_alloc (cfg->mempool, cfg->reverse_inst_list_len * sizeof (InstList));
850         }
851         mem = inst_list;
852
853         i = 1;
854         fpcount = 0;
855         DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb->block_num));
856         /* forward pass on the instructions to collect register liveness info */
857         for (ins = bb->code; ins; ins = ins->next) {
858                 spec = ins_get_spec (ins->opcode);
859
860                 if (G_UNLIKELY (spec == MONO_ARCH_CPU_SPEC)) {
861                         g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
862                 }
863                 
864                 DEBUG (mono_print_ins (i, ins));
865
866                 /*
867                  * TRACK FP STACK
868                  */
869 #if MONO_ARCH_USE_FPSTACK
870                 if (need_fpstack) {
871                         GList *spill;
872
873                         if (spec [MONO_INST_SRC1] == 'f') {
874                                 spill = g_list_first (fspill_list);
875                                 if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
876                                         reginfo [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
877                                         fspill_list = g_list_remove (fspill_list, spill->data);
878                                 } else
879                                         fpcount--;
880                         }
881
882                         if (spec [MONO_INST_SRC2] == 'f') {
883                                 spill = g_list_first (fspill_list);
884                                 if (spill) {
885                                         reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
886                                         fspill_list = g_list_remove (fspill_list, spill->data);
887                                         if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
888                                                 fspill++;
889                                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
890                                                 reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
891                                         }
892                                 } else
893                                         fpcount--;
894                         }
895
896                         if (dreg_is_fp (spec)) {
897                                 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
898                                         if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
899                                                 reginfo [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
900                                                 fspill++;
901                                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
902                                                 fpcount--;
903                                         }
904                                         fpcount++;
905                                 }
906                         }
907                 }
908 #endif
909
910                 if (spec [MONO_INST_SRC1]) {
911                         //reginfo [ins->sreg1].prev_use = reginfo [ins->sreg1].last_use;
912                         //reginfo [ins->sreg1].last_use = i;
913                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
914                                 /* The virtual register is allocated sequentially */
915                                 //reginfo [ins->sreg1 + 1].prev_use = reginfo [ins->sreg1 + 1].last_use;
916                                 //reginfo [ins->sreg1 + 1].last_use = i;
917                                 if (reginfo [ins->sreg1 + 1].born_in == 0 || reginfo [ins->sreg1 + 1].born_in > i)
918                                         reginfo [ins->sreg1 + 1].born_in = i;
919                         }
920                 } else {
921                         ins->sreg1 = -1;
922                 }
923                 if (spec [MONO_INST_SRC2]) {
924                         //reginfo [ins->sreg2].prev_use = reginfo [ins->sreg2].last_use;
925                         //reginfo [ins->sreg2].last_use = i;
926                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
927                                 /* The virtual register is allocated sequentially */
928                                 //reginfo [ins->sreg2 + 1].prev_use = reginfo [ins->sreg2 + 1].last_use;
929                                 //reginfo [ins->sreg2 + 1].last_use = i;
930                                 if (reginfo [ins->sreg2 + 1].born_in == 0 || reginfo [ins->sreg2 + 1].born_in > i)
931                                         reginfo [ins->sreg2 + 1].born_in = i;
932                         }
933                 } else {
934                         ins->sreg2 = -1;
935                 }
936                 if (spec [MONO_INST_DEST]) {
937                         int dest_dreg;
938
939                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
940                                 reginfo [ins->dreg].killed_in = i;
941                         //reginfo [ins->dreg].prev_use = reginfo [ins->dreg].last_use;
942                         //reginfo [ins->dreg].last_use = i;
943                         if (reginfo [ins->dreg].born_in == 0 || reginfo [ins->dreg].born_in > i)
944                                 reginfo [ins->dreg].born_in = i;
945
946                         dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
947                         if (dest_dreg != -1)
948                                 reginfo [ins->dreg].preferred_mask = (regmask (dest_dreg));
949
950                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
951                                 /* The virtual register is allocated sequentially */
952                                 //reginfo [ins->dreg + 1].prev_use = reginfo [ins->dreg + 1].last_use;
953                                 //reginfo [ins->dreg + 1].last_use = i;
954                                 if (reginfo [ins->dreg + 1].born_in == 0 || reginfo [ins->dreg + 1].born_in > i)
955                                         reginfo [ins->dreg + 1].born_in = i;
956                                 if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
957                                         reginfo [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
958                         }
959                 } else {
960                         ins->dreg = -1;
961                 }
962
963                 if (spec [MONO_INST_CLOB] == 'c') {
964                         /* A call instruction implicitly uses all registers in call->out_ireg_args */
965
966                         MonoCallInst *call = (MonoCallInst*)ins;
967                         GSList *list;
968
969                         list = call->out_ireg_args;
970                         if (list) {
971                                 while (list) {
972                                         guint32 regpair;
973                                         int reg, hreg;
974
975                                         regpair = (guint32)(gssize)(list->data);
976                                         hreg = regpair >> 24;
977                                         reg = regpair & 0xffffff;
978
979                                         //reginfo [reg].prev_use = reginfo [reg].last_use;
980                                         //reginfo [reg].last_use = i;
981
982                                         list = g_slist_next (list);
983                                 }
984                         }
985
986                         list = call->out_freg_args;
987                         if (!use_fpstack && list) {
988                                 while (list) {
989                                         guint32 regpair;
990                                         int reg, hreg;
991
992                                         regpair = (guint32)(gssize)(list->data);
993                                         hreg = regpair >> 24;
994                                         reg = regpair & 0xffffff;
995
996                                         //reginfo [reg].prev_use = reginfo [reg].last_use;
997                                         //reginfo [reg].last_use = i;
998
999                                         list = g_slist_next (list);
1000                                 }
1001                         }
1002                 }
1003
1004                 reversed = inst_list_prepend (mem, reversed, ins);
1005                 mem += sizeof (InstList);
1006                 ++i;
1007         }
1008
1009         // todo: check if we have anything left on fp stack, in verify mode?
1010         fspill = 0;
1011
1012         DEBUG (print_regtrack (reginfo, rs->next_vreg));
1013         tmp = reversed;
1014         while (tmp) {
1015                 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
1016                 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
1017                 int dreg_high, sreg1_high;
1018                 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
1019                 regmask_t dreg_fixed_mask, sreg1_fixed_mask, sreg2_fixed_mask;
1020                 const unsigned char *ip;
1021                 --i;
1022                 ins = tmp->data;
1023                 spec = ins_get_spec (ins->opcode);
1024                 prev_dreg = -1;
1025                 prev_sreg2 = -1;
1026                 clob_dreg = -1;
1027                 clob_reg = -1;
1028                 dest_dreg = -1;
1029                 dest_sreg1 = -1;
1030                 dest_sreg2 = -1;
1031                 prev_sreg1 = -1;
1032                 dreg_high = -1;
1033                 sreg1_high = -1;
1034                 dreg_mask = dreg_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1035                 sreg1_mask = sreg1_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1036                 sreg2_mask = sreg2_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1037
1038                 DEBUG (printf ("processing:"));
1039                 DEBUG (mono_print_ins (i, ins));
1040
1041                 ip = ins->cil_code;
1042
1043                 /*
1044                  * FIXED REGS
1045                  */
1046                 dest_sreg1 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC1]);
1047                 dest_sreg2 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC2]);
1048                 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
1049                 clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
1050                 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
1051
1052 #ifdef MONO_ARCH_INST_FIXED_MASK
1053                 sreg1_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC1]);
1054                 sreg2_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC2]);
1055                 dreg_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_DEST]);
1056 #else
1057                 sreg1_fixed_mask = sreg2_fixed_mask = dreg_fixed_mask = 0;
1058 #endif
1059
1060                 /*
1061                  * TRACK FP STACK
1062                  */
1063 #if MONO_ARCH_USE_FPSTACK
1064                 if (need_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
1065                         if (dreg_is_fp (spec)) {
1066                                 if (reginfo [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
1067                                         GList *spill_node;
1068                                         MonoInst *store;
1069                                         spill_node = g_list_first (fspill_list);
1070                                         g_assert (spill_node);
1071
1072                                         store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
1073                                         insert_before_ins (ins, tmp, store);
1074                                         fspill_list = g_list_remove (fspill_list, spill_node->data);
1075                                         fspill--;
1076                                 }
1077                         }
1078
1079                         if (spec [MONO_INST_SRC1] == 'f') {
1080                                 if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
1081                                         MonoInst *load;
1082                                         MonoInst *store = NULL;
1083
1084                                         if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1085                                                 GList *spill_node;
1086                                                 spill_node = g_list_first (fspill_list);
1087                                                 g_assert (spill_node);
1088
1089                                                 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);          
1090                                                 fspill_list = g_list_remove (fspill_list, spill_node->data);
1091                                         }
1092
1093                                         fspill++;
1094                                         fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1095                                         load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
1096                                         insert_before_ins (ins, tmp, load);
1097                                         if (store) 
1098                                                 insert_before_ins (load, tmp, store);
1099                                 }
1100                         }
1101
1102                         if (spec [MONO_INST_SRC2] == 'f') {
1103                                 if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
1104                                         MonoInst *load;
1105                                         MonoInst *store = NULL;
1106
1107                                         if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1108                                                 GList *spill_node;
1109
1110                                                 spill_node = g_list_first (fspill_list);
1111                                                 g_assert (spill_node);
1112                                                 if (spec [MONO_INST_SRC1] == 'f' && (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
1113                                                         spill_node = g_list_next (spill_node);
1114         
1115                                                 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
1116                                                 fspill_list = g_list_remove (fspill_list, spill_node->data);
1117                                         }
1118                                 
1119                                         fspill++;
1120                                         fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1121                                         load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
1122                                         insert_before_ins (ins, tmp, load);
1123                                         if (store) 
1124                                                 insert_before_ins (load, tmp, store);
1125                                 }
1126                         }
1127                 }
1128 #endif
1129
1130                 /*
1131                  * TRACK FIXED SREG2
1132                  */
1133                 if (dest_sreg2 != -1) {
1134                         if (rs->ifree_mask & (regmask (dest_sreg2))) {
1135                                 if (is_global_ireg (ins->sreg2)) {
1136                                         /* Argument already in hard reg, need to copy */
1137                                         MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1138                                         insert_before_ins (ins, tmp, copy);
1139                                 }
1140                                 else {
1141                                         val = rs->vassign [ins->sreg2];
1142                                         if (val == -1) {
1143                                                 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
1144                                                 assign_reg (cfg, rs, ins->sreg2, dest_sreg2, FALSE);
1145                                         } else if (val < -1) {
1146                                                 /* FIXME: */
1147                                                 g_assert_not_reached ();
1148                                         } else {
1149                                                 /* Argument already in hard reg, need to copy */
1150                                                 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, val, NULL, ip, FALSE);
1151                                                 insert_before_ins (ins, tmp, copy);
1152                                         }
1153                                 }
1154                         } else {
1155                                 int need_spill = TRUE;
1156
1157                                 dreg_mask &= ~ (regmask (dest_sreg2));
1158                                 sreg1_mask &= ~ (regmask (dest_sreg2));
1159
1160                                 /* 
1161                                  * First check if dreg is assigned to dest_sreg2, since we
1162                                  * can't spill a dreg.
1163                                  */
1164                                 val = rs->vassign [ins->dreg];
1165                                 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
1166                                         /* 
1167                                          * the destination register is already assigned to 
1168                                          * dest_sreg2: we need to allocate another register for it 
1169                                          * and then copy from this to dest_sreg2.
1170                                          */
1171                                         int new_dest;
1172                                         new_dest = alloc_int_reg (cfg, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg]);
1173                                         g_assert (new_dest >= 0);
1174                                         DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
1175
1176                                         prev_dreg = ins->dreg;
1177                                         assign_ireg (cfg, rs, ins->dreg, new_dest);
1178                                         clob_dreg = ins->dreg;
1179                                         create_copy_ins (cfg, dest_sreg2, new_dest, ins, ip, FALSE);
1180                                         mono_regstate_free_int (rs, dest_sreg2);
1181                                         need_spill = FALSE;
1182                                 }
1183
1184                                 if (is_global_ireg (ins->sreg2)) {
1185                                         MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1186                                         insert_before_ins (ins, tmp, copy);
1187                                 }
1188                                 else {
1189                                         val = rs->vassign [ins->sreg2];
1190                                         if (val == dest_sreg2) {
1191                                                 /* sreg2 is already assigned to the correct register */
1192                                                 need_spill = FALSE;
1193                                         }
1194                                         else if ((val >= 0) || (val < -1)) {
1195                                                 /* FIXME: sreg2 already assigned to another register */
1196                                                 g_assert_not_reached ();
1197                                         }
1198                                 }
1199
1200                                 if (need_spill) {
1201                                         DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1202                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
1203                                         mono_regstate_free_int (rs, dest_sreg2);
1204                                 }
1205
1206                                 if (!is_global_ireg (ins->sreg2))
1207                                         /* force-set sreg2 */
1208                                         assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1209                         }
1210                         ins->sreg2 = dest_sreg2;
1211                 }
1212
1213                 /*
1214                  * TRACK DREG
1215                  */
1216                 fp = dreg_is_fp (spec);
1217                 if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
1218                         prev_dreg = ins->dreg;
1219
1220                 if (spec [MONO_INST_DEST] == 'b') {
1221                         /* 
1222                          * The dest reg is read by the instruction, not written, so
1223                          * avoid allocating sreg1/sreg2 to the same reg.
1224                          */
1225                         if (dest_sreg1 != -1)
1226                                 dreg_mask &= ~ (regmask (dest_sreg1));
1227                         if (dest_sreg2 != -1)
1228                                 dreg_mask &= ~ (regmask (dest_sreg2));
1229
1230                         val = rassign (cfg, ins->dreg, fp);
1231                         if (is_soft_reg (ins->dreg, fp) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
1232                                 /* DREG is already allocated to a register needed for sreg1 */
1233                                 get_register_force_spilling (cfg, tmp, ins, ins->dreg, FALSE);
1234                                 mono_regstate_free_int (rs, val);
1235                         }
1236                 }
1237
1238                 /*
1239                  * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1240                  * various complex situations.
1241                  */
1242                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1243                         guint32 dreg2, dest_dreg2;
1244
1245                         g_assert (is_soft_reg (ins->dreg, fp));
1246
1247                         if (dest_dreg != -1) {
1248                                 if (rs->vassign [ins->dreg] != dest_dreg)
1249                                         free_up_ireg (cfg, tmp, ins, dest_dreg);
1250
1251                                 dreg2 = ins->dreg + 1;
1252                                 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
1253                                 if (dest_dreg2 != -1) {
1254                                         if (rs->vassign [dreg2] != dest_dreg2)
1255                                                 free_up_ireg (cfg, tmp, ins, dest_dreg2);
1256                                 }
1257                         }
1258                 }
1259
1260                 if (dreg_fixed_mask) {
1261                         g_assert (!fp);
1262                         if (is_global_ireg (ins->dreg)) {
1263                                 /* 
1264                                  * The argument is already in a hard reg, but that reg is
1265                                  * not usable by this instruction, so allocate a new one.
1266                                  */
1267                                 val = mono_regstate_alloc_int (rs, dreg_fixed_mask);
1268                                 if (val < 0)
1269                                         val = get_register_spilling (cfg, tmp, ins, dreg_fixed_mask, -1, fp);
1270                                 mono_regstate_free_int (rs, val);
1271                                 dest_dreg = val;
1272
1273                                 /* Fall through */
1274                         }
1275                         else
1276                                 dreg_mask &= dreg_fixed_mask;
1277                 }
1278
1279                 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
1280                         if (dest_dreg != -1)
1281                                 dreg_mask = (regmask (dest_dreg));
1282
1283                         val = rassign (cfg, ins->dreg, fp);
1284
1285                         if (val < 0) {
1286                                 int spill = 0;
1287                                 if (val < -1) {
1288                                         /* the register gets spilled after this inst */
1289                                         spill = -val -1;
1290                                 }
1291                                 val = alloc_reg (cfg, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg], fp);
1292                                 assign_reg (cfg, rs, ins->dreg, val, fp);
1293                                 if (spill)
1294                                         create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
1295                         }
1296                                 
1297                         DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
1298                         ins->dreg = val;
1299                 }
1300
1301                 /* Handle regpairs */
1302                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1303                         int reg2 = prev_dreg + 1;
1304
1305                         g_assert (!fp);
1306                         g_assert (prev_dreg > -1);
1307                         g_assert (!is_global_ireg (rs->vassign [prev_dreg]));
1308                         mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->vassign [prev_dreg]);
1309 #ifdef __i386__
1310                         /* bug #80489 */
1311                         mask &= ~regmask (X86_ECX);
1312 #endif
1313                         val = rs->vassign [reg2];
1314                         if (val < 0) {
1315                                 int spill = 0;
1316                                 if (val < -1) {
1317                                         /* the register gets spilled after this inst */
1318                                         spill = -val -1;
1319                                 }
1320                                 val = mono_regstate_alloc_int (rs, mask);
1321                                 if (val < 0)
1322                                         val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1323                                 if (spill)
1324                                         create_spilled_store (cfg, spill, val, reg2, ins, fp);
1325                         }
1326                         else {
1327                                 if (! (mask & (regmask (val)))) {
1328                                         val = mono_regstate_alloc_int (rs, mask);
1329                                         if (val < 0)
1330                                                 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1331
1332                                         /* Reallocate hreg to the correct register */
1333                                         create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
1334
1335                                         mono_regstate_free_int (rs, rs->vassign [reg2]);
1336                                 }
1337                         }                                       
1338
1339                         DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1340                         assign_reg (cfg, rs, reg2, val, fp);
1341
1342                         dreg_high = val;
1343                         ins->backend.reg3 = val;
1344
1345                         if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1346                                 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1347                                 mono_regstate_free_int (rs, val);
1348                         }
1349                 }
1350
1351                 if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && reginfo [prev_dreg].born_in >= i) {
1352                         /* 
1353                          * In theory, we could free up the hreg even if the vreg is alive,
1354                          * but branches inside bblocks force us to assign the same hreg
1355                          * to a vreg every time it is encountered.
1356                          */
1357                         int dreg = rassign (cfg, prev_dreg, fp);
1358                         g_assert (dreg >= 0);
1359                         DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, reginfo [prev_dreg].born_in));
1360                         if (fp)
1361                                 mono_regstate_free_float (rs, dreg);
1362                         else
1363                                 mono_regstate_free_int (rs, dreg);
1364                 }
1365
1366                 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1367                         /* this instruction only outputs to dest_dreg, need to copy */
1368                         create_copy_ins (cfg, ins->dreg, dest_dreg, ins, ip, fp);
1369                         ins->dreg = dest_dreg;
1370
1371                         if (fp) {
1372                                 if (rs->fsymbolic [dest_dreg] >= MONO_MAX_FREGS)
1373                                         free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1374                         }
1375                         else {
1376                                 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1377                                         free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1378                         }
1379                 }
1380
1381                 if (spec [MONO_INST_DEST] == 'b') {
1382                         /* 
1383                          * The dest reg is read by the instruction, not written, so
1384                          * avoid allocating sreg1/sreg2 to the same reg.
1385                          */
1386                         sreg1_mask &= ~ (regmask (ins->dreg));
1387                         sreg2_mask &= ~ (regmask (ins->dreg));
1388                 }
1389
1390                 /*
1391                  * TRACK CLOBBERING
1392                  */
1393                 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1394                         DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1395                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
1396                         mono_regstate_free_int (rs, clob_reg);
1397                 }
1398
1399                 if (spec [MONO_INST_CLOB] == 'c') {
1400                         int j, s, dreg, dreg2;
1401                         guint64 clob_mask;
1402
1403                         clob_mask = MONO_ARCH_CALLEE_REGS;
1404
1405                         /*
1406                          * Need to avoid spilling the dreg since the dreg is not really
1407                          * clobbered by the call.
1408                          */
1409                         if ((prev_dreg != -1) && !dreg_is_fp (spec))
1410                                 dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
1411                         else
1412                                 dreg = -1;
1413
1414                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
1415                                 dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (spec));
1416                         else
1417                                 dreg2 = -1;
1418
1419                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
1420                                 s = regmask (j);
1421                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
1422                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
1423                                         mono_regstate_free_int (rs, j);
1424                                 }
1425                         }
1426
1427                         if (!use_fpstack) {
1428                                 clob_mask = MONO_ARCH_CALLEE_FREGS;
1429                                 if ((prev_dreg != -1) && dreg_is_fp (spec))
1430                                         dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
1431                                 else
1432                                         dreg = -1;
1433
1434                                 for (j = 0; j < MONO_MAX_FREGS; ++j) {
1435                                         s = regmask (j);
1436                                         if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
1437                                                 get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
1438                                                 mono_regstate_free_float (rs, j);
1439                                         }
1440                                 }
1441                         }
1442                 }
1443
1444                 /*
1445                  * TRACK ARGUMENT REGS
1446                  */
1447                 if (spec [MONO_INST_CLOB] == 'c') {
1448                         MonoCallInst *call = (MonoCallInst*)ins;
1449                         GSList *list;
1450
1451                         /* 
1452                          * This needs to be done before assigning sreg1, so sreg1 will
1453                          * not be assigned one of the argument regs.
1454                          */
1455
1456                         /* 
1457                          * Assign all registers in call->out_reg_args to the proper 
1458                          * argument registers.
1459                          */
1460
1461                         list = call->out_ireg_args;
1462                         if (list) {
1463                                 while (list) {
1464                                         guint32 regpair;
1465                                         int reg, hreg;
1466
1467                                         regpair = (guint32)(gssize)(list->data);
1468                                         hreg = regpair >> 24;
1469                                         reg = regpair & 0xffffff;
1470
1471                                         assign_reg (cfg, rs, reg, hreg, FALSE);
1472
1473                                         sreg1_mask &= ~(regmask (hreg));
1474
1475                                         DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1476
1477                                         list = g_slist_next (list);
1478                                 }
1479                         }
1480
1481                         list = call->out_freg_args;
1482                         if (list && !use_fpstack) {
1483                                 while (list) {
1484                                         guint32 regpair;
1485                                         int reg, hreg;
1486
1487                                         regpair = (guint32)(gssize)(list->data);
1488                                         hreg = regpair >> 24;
1489                                         reg = regpair & 0xffffff;
1490
1491                                         assign_reg (cfg, rs, reg, hreg, TRUE);
1492
1493                                         DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
1494
1495                                         list = g_slist_next (list);
1496                                 }
1497                         }
1498                 }
1499
1500                 /*
1501                  * TRACK SREG1
1502                  */
1503                 fp = sreg1_is_fp (spec);
1504                 if ((!fp || (fp && !use_fpstack))) {
1505                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
1506                                 g_assert (is_soft_reg (ins->sreg1, fp));
1507
1508                                 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1509                                 if (dest_sreg1 != -1)
1510                                         g_assert (dest_sreg1 == ins->dreg);
1511                                 val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
1512                                 g_assert (val >= 0);
1513                                 assign_reg (cfg, rs, ins->sreg1, val, fp);
1514
1515                                 DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1516
1517                                 g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
1518                                 val = mono_regstate_alloc_int (rs, regmask (dreg_high));
1519                                 g_assert (val >= 0);
1520                                 assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
1521
1522                                 DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
1523
1524                                 /* Skip rest of this section */
1525                                 dest_sreg1 = -1;
1526                         }
1527
1528                         if (sreg1_fixed_mask) {
1529                                 g_assert (!fp);
1530                                 if (is_global_ireg (ins->sreg1)) {
1531                                         /* 
1532                                          * The argument is already in a hard reg, but that reg is
1533                                          * not usable by this instruction, so allocate a new one.
1534                                          */
1535                                         val = mono_regstate_alloc_int (rs, sreg1_fixed_mask);
1536                                         if (val < 0)
1537                                                 val = get_register_spilling (cfg, tmp, ins, sreg1_fixed_mask, -1, fp);
1538                                         mono_regstate_free_int (rs, val);
1539                                         dest_sreg1 = val;
1540
1541                                         /* Fall through to the dest_sreg1 != -1 case */
1542                                 }
1543                                 else
1544                                         sreg1_mask &= sreg1_fixed_mask;
1545                         }
1546
1547                         if (dest_sreg1 != -1) {
1548                                 sreg1_mask = regmask (dest_sreg1);
1549
1550                                 if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
1551                                         DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1552                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
1553                                         mono_regstate_free_int (rs, dest_sreg1);
1554                                 }
1555                                 if (is_global_ireg (ins->sreg1)) {
1556                                         /* The argument is already in a hard reg, need to copy */
1557                                         MonoInst *copy = create_copy_ins (cfg, dest_sreg1, ins->sreg1, NULL, ip, FALSE);
1558                                         insert_before_ins (ins, tmp, copy);
1559                                         ins->sreg1 = dest_sreg1;
1560                                 }
1561                         }
1562
1563                         if (is_soft_reg (ins->sreg1, fp)) {
1564                                 val = rassign (cfg, ins->sreg1, fp);
1565                                 prev_sreg1 = ins->sreg1;
1566                                 if (val < 0) {
1567                                         int spill = 0;
1568                                         if (val < -1) {
1569                                                 /* the register gets spilled after this inst */
1570                                                 spill = -val -1;
1571                                         }
1572
1573                                         if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
1574                                                 /* 
1575                                                  * Allocate the same hreg to sreg1 as well so the 
1576                                                  * peephole can get rid of the move.
1577                                                  */
1578                                                 sreg1_mask = regmask (ins->dreg);
1579                                         }
1580
1581                                         val = alloc_reg (cfg, tmp, ins, sreg1_mask, ins->sreg1, &reginfo [ins->sreg1], fp);
1582                                         assign_reg (cfg, rs, ins->sreg1, val, fp);
1583                                         DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1584
1585                                         if (spill) {
1586                                                 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
1587                                                 /*
1588                                                  * Need to insert before the instruction since it can
1589                                                  * overwrite sreg1.
1590                                                  */
1591                                                 insert_before_ins (ins, tmp, store);
1592                                         }
1593                                 }
1594                                 else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1595                                         create_copy_ins (cfg, dest_sreg1, val, ins, ip, fp);
1596                                 }
1597                                 
1598                                 ins->sreg1 = val;
1599                         }
1600                         else {
1601                                 prev_sreg1 = -1;
1602                         }
1603                         sreg2_mask &= ~(regmask (ins->sreg1));
1604                 }
1605
1606                 /* Handle the case when sreg1 is a regpair but dreg is not */
1607                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1]) && (spec [MONO_INST_CLOB] != '1')) {
1608                         int reg2 = prev_sreg1 + 1;
1609
1610                         g_assert (!fp);
1611                         g_assert (prev_sreg1 > -1);
1612                         g_assert (!is_global_ireg (rs->vassign [prev_sreg1]));
1613                         mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->vassign [prev_sreg1]);
1614                         val = rs->vassign [reg2];
1615                         if (val < 0) {
1616                                 int spill = 0;
1617                                 if (val < -1) {
1618                                         /* the register gets spilled after this inst */
1619                                         spill = -val -1;
1620                                 }
1621                                 val = mono_regstate_alloc_int (rs, mask);
1622                                 if (val < 0)
1623                                         val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1624                                 if (spill)
1625                                         g_assert_not_reached ();
1626                         }
1627                         else {
1628                                 if (! (mask & (regmask (val)))) {
1629                                         /* The vreg is already allocated to a wrong hreg */
1630                                         /* FIXME: */
1631                                         g_assert_not_reached ();
1632 #if 0
1633                                         val = mono_regstate_alloc_int (rs, mask);
1634                                         if (val < 0)
1635                                                 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1636
1637                                         /* Reallocate hreg to the correct register */
1638                                         create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
1639
1640                                         mono_regstate_free_int (rs, rs->vassign [reg2]);
1641 #endif
1642                                 }
1643                         }                                       
1644
1645                         sreg1_high = val;
1646                         DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1647                         assign_reg (cfg, rs, reg2, val, fp);
1648                 }
1649
1650                 /* Handle dreg==sreg1 */
1651                 if (((dreg_is_fp (spec) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1652                         MonoInst *sreg2_copy = NULL;
1653                         MonoInst *copy;
1654                         gboolean fp = (spec [MONO_INST_SRC1] == 'f');
1655
1656                         if (ins->dreg == ins->sreg2) {
1657                                 /* 
1658                                  * copying sreg1 to dreg could clobber sreg2, so allocate a new
1659                                  * register for it.
1660                                  */
1661                                 int reg2 = alloc_reg (cfg, tmp, ins, dreg_mask, ins->sreg2, NULL, fp);
1662
1663                                 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
1664                                 sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
1665                                 prev_sreg2 = ins->sreg2 = reg2;
1666
1667                                 if (fp)
1668                                         mono_regstate_free_float (rs, reg2);
1669                                 else
1670                                         mono_regstate_free_int (rs, reg2);
1671                         }
1672
1673                         if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
1674                                 /* Copying sreg1_high to dreg could also clobber sreg2 */
1675                                 if (rs->vassign [prev_sreg1 + 1] == ins->sreg2)
1676                                         /* FIXME: */
1677                                         g_assert_not_reached ();
1678
1679                                 /* 
1680                                  * sreg1 and dest are already allocated to the same regpair by the
1681                                  * SREG1 allocation code.
1682                                  */
1683                                 g_assert (ins->sreg1 == ins->dreg);
1684                                 g_assert (dreg_high == sreg1_high);
1685                         }
1686
1687                         DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
1688                         copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
1689                         insert_before_ins (ins, tmp, copy);
1690
1691                         if (sreg2_copy)
1692                                 insert_before_ins (copy, tmp, sreg2_copy);
1693
1694                         /*
1695                          * Need to prevent sreg2 to be allocated to sreg1, since that
1696                          * would screw up the previous copy.
1697                          */
1698                         sreg2_mask &= ~ (regmask (ins->sreg1));
1699                         /* we set sreg1 to dest as well */
1700                         prev_sreg1 = ins->sreg1 = ins->dreg;
1701                         sreg2_mask &= ~ (regmask (ins->dreg));
1702                 }
1703
1704                 /*
1705                  * TRACK SREG2
1706                  */
1707                 fp = sreg2_is_fp (spec);
1708                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
1709                         g_assert_not_reached ();
1710                 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
1711                         val = rassign (cfg, ins->sreg2, fp);
1712
1713                         if (val < 0) {
1714                                 int spill = 0;
1715                                 if (val < -1) {
1716                                         /* the register gets spilled after this inst */
1717                                         spill = -val -1;
1718                                 }
1719                                 val = alloc_reg (cfg, tmp, ins, sreg2_mask, ins->sreg2, &reginfo [ins->sreg2], fp);
1720                                 assign_reg (cfg, rs, ins->sreg2, val, fp);
1721                                 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
1722                                 if (spill) {
1723                                         MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg2, NULL, fp);
1724                                         /*
1725                                          * Need to insert before the instruction since it can
1726                                          * overwrite sreg2.
1727                                          */
1728                                         insert_before_ins (ins, tmp, store);
1729                                 }
1730                         }
1731                         ins->sreg2 = val;
1732                 }
1733                 else {
1734                         prev_sreg2 = -1;
1735                 }
1736
1737                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1738                         DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1739                         mono_regstate_free_int (rs, ins->sreg1);
1740                 }
1741                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1742                         DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1743                         mono_regstate_free_int (rs, ins->sreg2);
1744                 }*/
1745         
1746                 DEBUG (mono_print_ins (i, ins));
1747                 /* this may result from a insert_before call */
1748                 if (!tmp->next)
1749                         bb->code = tmp->data;
1750                 tmp = tmp->next;
1751         }
1752
1753         g_list_free (fspill_list);
1754 }
1755
1756 CompRelation
1757 mono_opcode_to_cond (int opcode)
1758 {
1759         switch (opcode) {
1760         case CEE_BEQ:
1761         case OP_CEQ:
1762         case OP_IBEQ:
1763         case OP_ICEQ:
1764         case OP_LBEQ:
1765         case OP_LCEQ:
1766         case OP_FBEQ:
1767         case OP_FCEQ:
1768         case OP_COND_EXC_EQ:
1769         case OP_COND_EXC_IEQ:
1770                 return CMP_EQ;
1771         case CEE_BNE_UN:
1772         case OP_IBNE_UN:
1773         case OP_LBNE_UN:
1774         case OP_FBNE_UN:
1775         case OP_COND_EXC_NE_UN:
1776         case OP_COND_EXC_INE_UN:
1777                 return CMP_NE;
1778         case CEE_BLE:
1779         case OP_IBLE:
1780         case OP_LBLE:
1781         case OP_FBLE:
1782                 return CMP_LE;
1783         case CEE_BGE:
1784         case OP_IBGE:
1785         case OP_LBGE:
1786         case OP_FBGE:
1787                 return CMP_GE;
1788         case CEE_BLT:
1789         case OP_CLT:
1790         case OP_IBLT:
1791         case OP_ICLT:
1792         case OP_LBLT:
1793         case OP_LCLT:
1794         case OP_FBLT:
1795         case OP_FCLT:
1796         case OP_COND_EXC_LT:
1797         case OP_COND_EXC_ILT:
1798                 return CMP_LT;
1799         case CEE_BGT:
1800         case OP_CGT:
1801         case OP_IBGT:
1802         case OP_ICGT:
1803         case OP_LBGT:
1804         case OP_LCGT:
1805         case OP_FBGT:
1806         case OP_FCGT:
1807         case OP_COND_EXC_GT:
1808         case OP_COND_EXC_IGT:
1809                 return CMP_GT;
1810
1811         case CEE_BLE_UN:
1812         case OP_IBLE_UN:
1813         case OP_LBLE_UN:
1814         case OP_FBLE_UN:
1815         case OP_COND_EXC_LE_UN:
1816         case OP_COND_EXC_ILE_UN:
1817                 return CMP_LE_UN;
1818         case CEE_BGE_UN:
1819         case OP_IBGE_UN:
1820         case OP_LBGE_UN:
1821         case OP_FBGE_UN:
1822                 return CMP_GE_UN;
1823         case CEE_BLT_UN:
1824         case OP_CLT_UN:
1825         case OP_IBLT_UN:
1826         case OP_ICLT_UN:
1827         case OP_LBLT_UN:
1828         case OP_LCLT_UN:
1829         case OP_FBLT_UN:
1830         case OP_FCLT_UN:
1831         case OP_COND_EXC_LT_UN:
1832         case OP_COND_EXC_ILT_UN:
1833                 return CMP_LT_UN;
1834         case CEE_BGT_UN:
1835         case OP_CGT_UN:
1836         case OP_IBGT_UN:
1837         case OP_ICGT_UN:
1838         case OP_LBGT_UN:
1839         case OP_LCGT_UN:
1840         case OP_FCGT_UN:
1841         case OP_FBGT_UN:
1842         case OP_COND_EXC_GT_UN:
1843         case OP_COND_EXC_IGT_UN:
1844                 return CMP_GT_UN;
1845         default:
1846                 printf ("%s\n", mono_inst_name (opcode));
1847                 g_assert_not_reached ();
1848         }
1849 }
1850
1851 CompType
1852 mono_opcode_to_type (int opcode, int cmp_opcode)
1853 {
1854         if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1855                 return CMP_TYPE_L;
1856         else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1857                 return CMP_TYPE_L;
1858         else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLE_UN))
1859                 return CMP_TYPE_I;
1860         else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1861                 return CMP_TYPE_I;
1862         else if ((opcode >= OP_LBEQ) && (opcode <= OP_LBLT_UN))
1863                 return CMP_TYPE_L;
1864         else if ((opcode >= OP_LCEQ) && (opcode <= OP_LCLT_UN))
1865                 return CMP_TYPE_L;
1866         else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLE_UN))
1867                 return CMP_TYPE_F;
1868         else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1869                 return CMP_TYPE_F;
1870         else if ((opcode >= OP_COND_EXC_IEQ) && (opcode <= OP_COND_EXC_ILT_UN))
1871                 return CMP_TYPE_I;
1872         else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1873                 switch (cmp_opcode) {
1874                 case OP_ICOMPARE:
1875                 case OP_ICOMPARE_IMM:
1876                         return CMP_TYPE_I;
1877                 default:
1878                         return CMP_TYPE_L;
1879                 }
1880         } else {
1881                 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1882                 return 0;
1883         }
1884 }
1885
1886 gboolean
1887 mono_is_regsize_var (MonoType *t)
1888 {
1889         if (t->byref)
1890                 return TRUE;
1891         t = mono_type_get_underlying_type (t);
1892         switch (t->type) {
1893         case MONO_TYPE_BOOLEAN:
1894         case MONO_TYPE_CHAR:
1895         case MONO_TYPE_I1:
1896         case MONO_TYPE_U1:
1897         case MONO_TYPE_I2:
1898         case MONO_TYPE_U2:
1899         case MONO_TYPE_I4:
1900         case MONO_TYPE_U4:
1901         case MONO_TYPE_I:
1902         case MONO_TYPE_U:
1903         case MONO_TYPE_PTR:
1904         case MONO_TYPE_FNPTR:
1905 #if SIZEOF_VOID_P == 8
1906         case MONO_TYPE_I8:
1907         case MONO_TYPE_U8:
1908 #endif
1909                 return TRUE;
1910         case MONO_TYPE_OBJECT:
1911         case MONO_TYPE_STRING:
1912         case MONO_TYPE_CLASS:
1913         case MONO_TYPE_SZARRAY:
1914         case MONO_TYPE_ARRAY:
1915                 return TRUE;
1916         case MONO_TYPE_GENERICINST:
1917                 if (!mono_type_generic_inst_is_valuetype (t))
1918                         return TRUE;
1919                 return FALSE;
1920         case MONO_TYPE_VALUETYPE:
1921                 return FALSE;
1922         }
1923         return FALSE;
1924 }