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