2008-10-21 Rodrigo Kumpera <rkumpera@novell.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 #ifndef MONO_MAX_XREGS
25
26 #define MONO_MAX_XREGS 0
27 #define MONO_ARCH_CALLEE_SAVED_XREGS 0
28 #define MONO_ARCH_CALLEE_XREGS 0
29
30 #endif
31 /*
32  * Every hardware register belongs to a register type or register bank. bank 0 
33  * contains the int registers, bank 1 contains the fp registers.
34  * int registers are used 99% of the time, so they are special cased in a lot of 
35  * places.
36  */
37
38 static const int regbank_size [] = {
39         MONO_MAX_IREGS,
40         MONO_MAX_FREGS,
41         MONO_MAX_XREGS
42 };
43
44 static const int regbank_load_ops [] = { 
45         OP_LOAD_MEMBASE,
46         OP_LOADR8_MEMBASE,
47         OP_LOADX_MEMBASE
48 };
49
50 static const int regbank_store_ops [] = { 
51         OP_STORE_MEMBASE_REG,
52         OP_STORER8_MEMBASE_REG,
53         OP_STOREX_MEMBASE
54 };
55
56 static const int regbank_move_ops [] = { 
57         OP_MOVE,
58         OP_FMOVE,
59         OP_XMOVE
60 };
61
62 #define regmask(reg) (((regmask_t)1) << (reg))
63
64 static const regmask_t regbank_callee_saved_regs [] = {
65         MONO_ARCH_CALLEE_SAVED_REGS,
66         MONO_ARCH_CALLEE_SAVED_FREGS,
67         MONO_ARCH_CALLEE_SAVED_XREGS,
68 };
69
70 static const regmask_t regbank_callee_regs [] = {
71         MONO_ARCH_CALLEE_REGS,
72         MONO_ARCH_CALLEE_FREGS,
73         MONO_ARCH_CALLEE_XREGS,
74 };
75
76 static const int regbank_spill_var_size[] = {
77         sizeof (gpointer),
78         sizeof (double),
79         16 /*FIXME make this a constant. Maybe MONO_ARCH_SIMD_VECTOR_SIZE? */
80 };
81
82 #define DEBUG(a) MINI_DEBUG(cfg->verbose_level, 3, a;)
83
84 static inline GSList*
85 g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
86 {
87         GSList *new_list;
88         GSList *last;
89         
90         new_list = mono_mempool_alloc (mp, sizeof (GSList));
91         new_list->data = data;
92         new_list->next = NULL;
93         
94         if (list) {
95                 last = list;
96                 while (last->next)
97                         last = last->next;
98                 last->next = new_list;
99                 
100                 return list;
101         } else
102                 return new_list;
103 }
104
105 static inline void
106 mono_regstate_assign (MonoRegState *rs)
107 {
108         if (rs->next_vreg > rs->vassign_size) {
109                 g_free (rs->vassign);
110                 rs->vassign_size = MAX (rs->next_vreg, 256);
111                 rs->vassign = g_malloc (rs->vassign_size * sizeof (int));
112         }
113
114         memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
115         memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
116
117         rs->symbolic [0] = rs->isymbolic;
118         rs->symbolic [1] = rs->fsymbolic;
119
120 #ifdef MONO_ARCH_NEED_SIMD_BANK
121         memset (rs->xsymbolic, 0, MONO_MAX_XREGS * sizeof (rs->xsymbolic [0]));
122         rs->symbolic [2] = rs->xsymbolic;
123 #endif
124 }
125
126 static inline int
127 mono_regstate_alloc_int (MonoRegState *rs, regmask_t allow)
128 {
129         regmask_t mask = allow & rs->ifree_mask;
130
131 #if defined(__x86_64__) && defined(__GNUC__)
132  {
133         guint64 i;
134
135         if (mask == 0)
136                 return -1;
137
138         __asm__("bsfq %1,%0\n\t"
139                         : "=r" (i) : "rm" (mask));
140
141         rs->ifree_mask &= ~ ((regmask_t)1 << i);
142         return i;
143  }
144 #else
145         int i;
146
147         for (i = 0; i < MONO_MAX_IREGS; ++i) {
148                 if (mask & ((regmask_t)1 << i)) {
149                         rs->ifree_mask &= ~ ((regmask_t)1 << i);
150                         return i;
151                 }
152         }
153         return -1;
154 #endif
155 }
156
157 static inline void
158 mono_regstate_free_int (MonoRegState *rs, int reg)
159 {
160         if (reg >= 0) {
161                 rs->ifree_mask |= (regmask_t)1 << reg;
162                 rs->isymbolic [reg] = 0;
163         }
164 }
165
166 static inline int
167 mono_regstate_alloc_general (MonoRegState *rs, regmask_t allow, int bank)
168 {
169         int i;
170         regmask_t mask = allow & rs->free_mask [bank];
171         for (i = 0; i < regbank_size [bank]; ++i) {
172                 if (mask & ((regmask_t)1 << i)) {
173                         rs->free_mask [bank] &= ~ ((regmask_t)1 << i);
174                         return i;
175                 }
176         }
177         return -1;
178 }
179
180 static inline void
181 mono_regstate_free_general (MonoRegState *rs, int reg, int bank)
182 {
183         if (reg >= 0) {
184                 rs->free_mask [bank] |= (regmask_t)1 << reg;
185                 rs->symbolic [bank][reg] = 0;
186         }
187 }
188
189 const char*
190 mono_regname_full (int reg, int bank)
191 {
192         if (G_UNLIKELY (bank)) {
193 #if MONO_ARCH_NEED_SIMD_BANK
194                 if (bank == 2)
195                         return mono_arch_xregname (reg);
196 #endif
197                 g_assert (bank == 1);
198                 return mono_arch_fregname (reg);
199         } else {
200                 return mono_arch_regname (reg);
201         }
202 }
203
204 void
205 mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, int bank)
206 {
207         guint32 regpair;
208
209         regpair = (((guint32)hreg) << 24) + vreg;
210         if (G_UNLIKELY (bank)) {
211                 g_assert (vreg >= regbank_size [bank]);
212                 g_assert (hreg < regbank_size [bank]);
213                 call->used_fregs |= 1 << hreg;
214                 call->out_freg_args = g_slist_append_mempool (cfg->mempool, call->out_freg_args, (gpointer)(gssize)(regpair));
215         } else {
216                 g_assert (vreg >= MONO_MAX_IREGS);
217                 g_assert (hreg < MONO_MAX_IREGS);
218                 call->used_iregs |= 1 << hreg;
219                 call->out_ireg_args = g_slist_append_mempool (cfg->mempool, call->out_ireg_args, (gpointer)(gssize)(regpair));
220         }
221 }
222
223 static void
224 resize_spill_info (MonoCompile *cfg, int bank)
225 {
226         MonoSpillInfo *orig_info = cfg->spill_info [bank];
227         int orig_len = cfg->spill_info_len [bank];
228         int new_len = orig_len ? orig_len * 2 : 16;
229         MonoSpillInfo *new_info;
230         int i;
231
232         g_assert (bank < MONO_NUM_REGBANKS);
233
234         new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
235         if (orig_info)
236                 memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
237         for (i = orig_len; i < new_len; ++i)
238                 new_info [i].offset = -1;
239
240         cfg->spill_info [bank] = new_info;
241         cfg->spill_info_len [bank] = new_len;
242 }
243
244 /*
245  * returns the offset used by spillvar. It allocates a new
246  * spill variable if necessary. 
247  */
248 static inline int
249 mono_spillvar_offset (MonoCompile *cfg, int spillvar, int bank)
250 {
251         MonoSpillInfo *info;
252         int size;
253
254 #if defined (__mips__)
255         g_assert_not_reached();
256 #endif
257         if (G_UNLIKELY (spillvar >= (cfg->spill_info_len [bank]))) {
258                 while (spillvar >= cfg->spill_info_len [bank])
259                         resize_spill_info (cfg, bank);
260         }
261
262         /*
263          * Allocate separate spill slots for fp/non-fp variables since most processors prefer it.
264          */
265         info = &cfg->spill_info [bank][spillvar];
266         if (info->offset == -1) {
267                 cfg->stack_offset += sizeof (gpointer) - 1;
268                 cfg->stack_offset &= ~(sizeof (gpointer) - 1);
269
270                 g_assert (bank < MONO_NUM_REGBANKS);
271                 if (G_UNLIKELY (bank))
272                         size = regbank_spill_var_size [bank];
273                 else
274                         size = sizeof (gpointer);
275
276                 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
277                         cfg->stack_offset += size - 1;
278                         cfg->stack_offset &= ~(size - 1);
279                         info->offset = cfg->stack_offset;
280                         cfg->stack_offset += size;
281                 } else {
282                         cfg->stack_offset += size - 1;
283                         cfg->stack_offset &= ~(size - 1);
284                         cfg->stack_offset += size;
285                         info->offset = - cfg->stack_offset;
286                 }
287         }
288
289         return info->offset;
290 }
291
292 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
293 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
294 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
295 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
296 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
297 #define is_local_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
298
299 #define is_hard_reg(r,bank) (G_UNLIKELY (bank) ? ((r) >= 0 && (r) < regbank_size [bank]) : ((r) < MONO_MAX_IREGS))
300 #define is_soft_reg(r,bank) (!is_hard_reg((r),(bank)))
301 #define is_global_reg(r,bank) (G_UNLIKELY (bank) ? (is_hard_reg ((r), (bank)) && (regbank_callee_saved_regs [bank] & regmask (r))) : is_global_ireg (r))
302 #define is_local_reg(r,bank) (G_UNLIKELY (bank) ? (is_hard_reg ((r), (bank)) && (regbank_callee_regs [bank] & regmask (r))) : is_local_ireg (r))
303 #define reg_is_freeable(r,bank) (G_UNLIKELY (bank) ? is_local_reg ((r), (bank)) : is_local_ireg ((r)))
304
305 #ifndef MONO_ARCH_INST_IS_FLOAT
306 #define MONO_ARCH_INST_IS_FLOAT(desc) ((desc) == 'f')
307 #endif
308
309 #define reg_is_fp(desc) (MONO_ARCH_INST_IS_FLOAT (desc))
310 #define dreg_is_fp(spec)  (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
311 #define sreg1_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC1]))
312 #define sreg2_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC2]))
313
314 #define reg_is_simd(desc) ((desc) == 'x') 
315
316 #ifdef MONO_ARCH_NEED_SIMD_BANK
317
318 #define reg_bank(desc) (G_UNLIKELY (reg_is_fp (desc)) ? MONO_REG_DOUBLE : G_UNLIKELY (reg_is_simd(desc)) ? MONO_REG_SIMD : MONO_REG_INT)
319
320 #else
321
322 #define reg_bank(desc) reg_is_fp ((desc))
323
324 #endif
325
326 #define sreg1_bank(spec) reg_bank ((spec)[MONO_INST_SRC1])
327 #define sreg2_bank(spec) reg_bank ((spec)[MONO_INST_SRC2])
328 #define dreg_bank(spec) reg_bank ((spec)[MONO_INST_DEST])
329
330 #define sreg1_bank_ins(ins) sreg1_bank (ins_get_spec ((ins)->opcode))
331 #define sreg2_bank_ins(ins) sreg2_bank (ins_get_spec ((ins)->opcode))
332 #define dreg_bank_ins(ins) dreg_bank (ins_get_spec ((ins)->opcode))
333
334 #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)
335
336 #ifdef MONO_ARCH_IS_GLOBAL_IREG
337 #undef is_global_ireg
338 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
339 #endif
340
341 typedef struct {
342         int born_in;
343         int killed_in;
344         /* Not (yet) used */
345         //int last_use;
346         //int prev_use;
347         regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
348 } RegTrack;
349
350 #ifndef DISABLE_LOGGING
351 void
352 mono_print_ins_index (int i, MonoInst *ins)
353 {
354         const char *spec = ins_get_spec (ins->opcode);
355
356         if (i != -1)
357                 printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
358         else
359                 printf (" %s", mono_inst_name (ins->opcode));
360         if (spec == MONO_ARCH_CPU_SPEC) {
361                 /* This is a lowered opcode */
362                 if (ins->dreg != -1)
363                         printf (" R%d <-", ins->dreg);
364                 if (ins->sreg1 != -1)
365                         printf (" R%d", ins->sreg1);
366                 if (ins->sreg2 != -1)
367                         printf (" R%d", ins->sreg2);
368
369                 switch (ins->opcode) {
370                 case OP_LBNE_UN:
371                 case OP_LBEQ:
372                 case OP_LBLT:
373                 case OP_LBLT_UN:
374                 case OP_LBGT:
375                 case OP_LBGT_UN:
376                 case OP_LBGE:
377                 case OP_LBGE_UN:
378                 case OP_LBLE:
379                 case OP_LBLE_UN:
380                         if (!(ins->flags & MONO_INST_BRLABEL)) {
381                                 if (!ins->inst_false_bb)
382                                         printf (" [B%d]", ins->inst_true_bb->block_num);
383                                 else
384                                         printf (" [B%dB%d]", ins->inst_true_bb->block_num, ins->inst_false_bb->block_num);
385                         }
386                         break;
387                 case OP_PHI:
388                 case OP_FPHI: {
389                         int i;
390                         printf (" [%d (", (int)ins->inst_c0);
391                         for (i = 0; i < ins->inst_phi_args [0]; i++) {
392                                 if (i)
393                                         printf (", ");
394                                 printf ("R%d", ins->inst_phi_args [i + 1]);
395                         }
396                         printf (")]");
397                         break;
398                 }
399                 case OP_LDADDR:
400                 case OP_OUTARG_VTRETADDR:
401                         printf (" R%d", ((MonoInst*)ins->inst_p0)->dreg);
402                         break;
403                 case OP_REGOFFSET:
404                         printf (" + 0x%lx", (long)ins->inst_offset);
405                 default:
406                         break;
407                 }
408
409                 printf ("\n");
410                 //g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
411                 return;
412         }
413
414         if (spec [MONO_INST_DEST]) {
415                 int bank = dreg_bank (spec);
416                 if (is_soft_reg (ins->dreg, bank)) {
417                         if (spec [MONO_INST_DEST] == 'b') {
418                                 if (ins->inst_offset == 0)
419                                         printf (" [R%d] <-", ins->dreg);
420                                 else
421                                         printf (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
422                         }
423                         else
424                                 printf (" R%d <-", ins->dreg);
425                 } else if (spec [MONO_INST_DEST] == 'b') {
426                         if (ins->inst_offset == 0)
427                                 printf (" [%s] <-", mono_arch_regname (ins->dreg));
428                         else
429                                 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
430                 } else
431                         printf (" %s <-", mono_regname_full (ins->dreg, bank));
432         }
433         if (spec [MONO_INST_SRC1]) {
434                 int bank = sreg1_bank (spec);
435                 if (is_soft_reg (ins->sreg1, bank)) {
436                         if (spec [MONO_INST_SRC1] == 'b')
437                                 printf (" [R%d + 0x%lx]", ins->sreg1, (long)ins->inst_offset);
438                         else
439                                 printf (" R%d", ins->sreg1);
440                 } else if (spec [MONO_INST_SRC1] == 'b')
441                         printf (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
442                 else
443                         printf (" %s", mono_regname_full (ins->sreg1, bank));
444         }
445         if (spec [MONO_INST_SRC2]) {
446                 int bank = sreg2_bank (spec);
447                 if (is_soft_reg (ins->sreg2, bank))
448                         printf (" R%d", ins->sreg2);
449                 else
450                         printf (" %s", mono_regname_full (ins->sreg2, bank));
451         }
452
453         switch (ins->opcode) {
454         case OP_ICONST:
455                 printf (" [%d]", (int)ins->inst_c0);
456                 break;
457 #if defined(__i386__) || defined(__x86_64__)
458         case OP_X86_PUSH_IMM:
459 #endif
460         case OP_ICOMPARE_IMM:
461         case OP_COMPARE_IMM:
462         case OP_IADD_IMM:
463         case OP_ISUB_IMM:
464         case OP_IAND_IMM:
465         case OP_IOR_IMM:
466         case OP_IXOR_IMM:
467                 printf (" [%d]", (int)ins->inst_imm);
468                 break;
469         case OP_ADD_IMM:
470         case OP_LADD_IMM:
471                 printf (" [%d]", (int)(gssize)ins->inst_p1);
472                 break;
473         case OP_I8CONST:
474                 printf (" [%lld]", (long long)ins->inst_l);
475                 break;
476         case OP_R8CONST:
477                 printf (" [%f]", *(double*)ins->inst_p0);
478                 break;
479         case OP_R4CONST:
480                 printf (" [%f]", *(float*)ins->inst_p0);
481                 break;
482         case CEE_CALL:
483         case CEE_CALLVIRT:
484         case OP_CALL:
485         case OP_CALL_MEMBASE:
486         case OP_CALL_REG:
487         case OP_FCALL:
488         case OP_FCALLVIRT:
489         case OP_LCALL:
490         case OP_LCALLVIRT:
491         case OP_VCALL:
492         case OP_VCALLVIRT:
493         case OP_VCALL_REG:
494         case OP_VCALL_MEMBASE:
495         case OP_VCALL2:
496         case OP_VCALL2_REG:
497         case OP_VCALL2_MEMBASE:
498         case OP_VOIDCALL:
499         case OP_VOIDCALLVIRT: {
500                 MonoCallInst *call = (MonoCallInst*)ins;
501                 GSList *list;
502
503                 if (ins->opcode == OP_VCALL || ins->opcode == OP_VCALL_REG || ins->opcode == OP_VCALL_MEMBASE) {
504                         /*
505                          * These are lowered opcodes, but they are in the .md files since the old 
506                          * JIT passes them to backends.
507                          */
508                         if (ins->dreg != -1)
509                                 printf (" R%d <-", ins->dreg);
510                 }
511
512                 if (call->method) {
513                         char *full_name = mono_method_full_name (call->method, TRUE);
514                         printf (" [%s]", full_name);
515                         g_free (full_name);
516                 } else if (call->fptr) {
517                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
518                         if (info)
519                                 printf (" [%s]", info->name);
520                 }
521
522                 list = call->out_ireg_args;
523                 while (list) {
524                         guint32 regpair;
525                         int reg, hreg;
526
527                         regpair = (guint32)(gssize)(list->data);
528                         hreg = regpair >> 24;
529                         reg = regpair & 0xffffff;
530
531                         printf (" [%s <- R%d]", mono_arch_regname (hreg), reg);
532
533                         list = g_slist_next (list);
534                 }
535                 break;
536         }
537         case OP_BR:
538         case OP_CALL_HANDLER:
539                 printf (" [B%d]", ins->inst_target_bb->block_num);
540                 break;
541         case CEE_BNE_UN:
542         case CEE_BEQ:
543         case CEE_BLT:
544         case CEE_BLT_UN:
545         case CEE_BGT:
546         case CEE_BGT_UN:
547         case CEE_BGE:
548         case CEE_BGE_UN:
549         case CEE_BLE:
550         case CEE_BLE_UN:
551         case OP_IBNE_UN:
552         case OP_IBEQ:
553         case OP_IBLT:
554         case OP_IBLT_UN:
555         case OP_IBGT:
556         case OP_IBGT_UN:
557         case OP_IBGE:
558         case OP_IBGE_UN:
559         case OP_IBLE:
560         case OP_IBLE_UN:
561         case OP_LBNE_UN:
562         case OP_LBEQ:
563         case OP_LBLT:
564         case OP_LBLT_UN:
565         case OP_LBGT:
566         case OP_LBGT_UN:
567         case OP_LBGE:
568         case OP_LBGE_UN:
569         case OP_LBLE:
570         case OP_LBLE_UN:
571                 if (!(ins->flags & MONO_INST_BRLABEL)) {
572                         if (!ins->inst_false_bb)
573                                 printf (" [B%d]", ins->inst_true_bb->block_num);
574                         else
575                                 printf (" [B%dB%d]", ins->inst_true_bb->block_num, ins->inst_false_bb->block_num);
576                 }
577                 break;
578         default:
579                 break;
580         }
581
582         if (spec [MONO_INST_CLOB])
583                 printf (" clobbers: %c", spec [MONO_INST_CLOB]);
584         printf ("\n");
585 }
586
587 static void
588 print_regtrack (RegTrack *t, int num)
589 {
590         int i;
591         char buf [32];
592         const char *r;
593         
594         for (i = 0; i < num; ++i) {
595                 if (!t [i].born_in)
596                         continue;
597                 if (i >= MONO_MAX_IREGS) {
598                         g_snprintf (buf, sizeof(buf), "R%d", i);
599                         r = buf;
600                 } else
601                         r = mono_arch_regname (i);
602                 printf ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].killed_in);
603         }
604 }
605 #else
606 void
607 mono_print_ins_index (int i, MonoInst *ins)
608 {
609 }
610 #endif /* DISABLE_LOGGING */
611
612 void
613 mono_print_ins (MonoInst *ins)
614 {
615         mono_print_ins_index (-1, ins);
616 }
617
618 static inline void
619 insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst* to_insert)
620 {
621         /*
622          * If this function is called multiple times, the new instructions are inserted
623          * in the proper order.
624          */
625         mono_bblock_insert_before_ins (bb, ins, to_insert);
626 }
627
628 static inline void
629 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst **last, MonoInst* to_insert)
630 {
631         /*
632          * If this function is called multiple times, the new instructions are inserted in
633          * proper order.
634          */
635         mono_bblock_insert_after_ins (bb, *last, to_insert);
636
637         *last = to_insert;
638 }
639
640 /*
641  * Force the spilling of the variable in the symbolic register 'reg'.
642  */
643 static int
644 get_register_force_spilling (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins, int reg, int bank)
645 {
646         MonoInst *load;
647         int i, sel, spill;
648         int *symbolic;
649         MonoRegState *rs = cfg->rs;
650
651         symbolic = rs->symbolic [bank];
652         sel = rs->vassign [reg];
653
654         /*i = rs->isymbolic [sel];
655         g_assert (i == reg);*/
656         i = reg;
657         spill = ++cfg->spill_count;
658         rs->vassign [i] = -spill - 1;
659         if (G_UNLIKELY (bank))
660                 mono_regstate_free_general (rs, sel, bank);
661         else
662                 mono_regstate_free_int (rs, sel);
663         /* we need to create a spill var and insert a load to sel after the current instruction */
664         MONO_INST_NEW (cfg, load, regbank_load_ops [bank]);
665         load->dreg = sel;
666         load->inst_basereg = cfg->frame_reg;
667         load->inst_offset = mono_spillvar_offset (cfg, spill, bank);
668         insert_after_ins (bb, ins, last, load);
669         DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, bank)));
670         if (G_UNLIKELY (bank))
671                 i = mono_regstate_alloc_general (rs, regmask (sel), bank);
672         else
673                 i = mono_regstate_alloc_int (rs, regmask (sel));
674         g_assert (i == sel);
675
676         return sel;
677 }
678
679 /* This isn't defined on older glib versions and on some platforms */
680 #ifndef G_GUINT64_FORMAT
681 #define G_GUINT64_FORMAT "ul"
682 #endif
683
684 static int
685 get_register_spilling (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins, regmask_t regmask, int reg, int bank)
686 {
687         MonoInst *load;
688         int i, sel, spill;
689         int *symbolic;
690         MonoRegState *rs = cfg->rs;
691
692         symbolic = rs->symbolic [bank];
693
694         g_assert (bank < MONO_NUM_REGBANKS);
695
696         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));
697         /* exclude the registers in the current instruction */
698         if ((sreg1_bank_ins (ins) == bank) && (reg != ins->sreg1) && (reg_is_freeable (ins->sreg1, bank) || (is_soft_reg (ins->sreg1, bank) && rs->vassign [ins->sreg1] >= 0))) {
699                 if (is_soft_reg (ins->sreg1, bank))
700                         regmask &= ~ (regmask (rs->vassign [ins->sreg1]));
701                 else
702                         regmask &= ~ (regmask (ins->sreg1));
703                 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, bank)));
704         }
705         if ((sreg2_bank_ins (ins) == bank) && (reg != ins->sreg2) && (reg_is_freeable (ins->sreg2, bank) || (is_soft_reg (ins->sreg2, bank) && rs->vassign [ins->sreg2] >= 0))) {
706                 if (is_soft_reg (ins->sreg2, bank))
707                         regmask &= ~ (regmask (rs->vassign [ins->sreg2]));
708                 else
709                         regmask &= ~ (regmask (ins->sreg2));
710                 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, bank), ins->sreg2));
711         }
712         if ((dreg_bank_ins (ins) == bank) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, bank)) {
713                 regmask &= ~ (regmask (ins->dreg));
714                 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, bank)));
715         }
716
717         DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
718         g_assert (regmask); /* need at least a register we can free */
719         sel = 0;
720         /* we should track prev_use and spill the register that's farther */
721         if (G_UNLIKELY (bank)) {
722                 for (i = 0; i < regbank_size [bank]; ++i) {
723                         if (regmask & (regmask (i))) {
724                                 sel = i;
725                                 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_regname_full (sel, bank), rs->symbolic [bank] [sel]));
726                                 break;
727                         }
728                 }
729
730                 i = rs->symbolic [bank] [sel];
731                 spill = ++cfg->spill_count;
732                 rs->vassign [i] = -spill - 1;
733                 mono_regstate_free_general (rs, sel, bank);
734         }
735         else {
736                 for (i = 0; i < MONO_MAX_IREGS; ++i) {
737                         if (regmask & (regmask (i))) {
738                                 sel = i;
739                                 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), rs->isymbolic [sel]));
740                                 break;
741                         }
742                 }
743
744                 i = rs->isymbolic [sel];
745                 spill = ++cfg->spill_count;
746                 rs->vassign [i] = -spill - 1;
747                 mono_regstate_free_int (rs, sel);
748         }
749
750         /* we need to create a spill var and insert a load to sel after the current instruction */
751         MONO_INST_NEW (cfg, load, regbank_load_ops [bank]);
752         load->dreg = sel;
753         load->inst_basereg = cfg->frame_reg;
754         load->inst_offset = mono_spillvar_offset (cfg, spill, bank);
755         insert_after_ins (bb, ins, last, load);
756         DEBUG (printf ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, bank)));
757         if (G_UNLIKELY (bank))
758                 i = mono_regstate_alloc_general (rs, regmask (sel), bank);
759         else
760                 i = mono_regstate_alloc_int (rs, regmask (sel));
761         g_assert (i == sel);
762         
763         return sel;
764 }
765
766 static void
767 free_up_reg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins, int hreg, int bank)
768 {
769         if (G_UNLIKELY (bank)) {
770                 if (!(cfg->rs->free_mask [1] & (regmask (hreg)))) {
771                         DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->symbolic [bank] [hreg]));
772                         get_register_force_spilling (cfg, bb, last, ins, cfg->rs->symbolic [bank] [hreg], bank);
773                         mono_regstate_free_general (cfg->rs, hreg, bank);
774                 }
775         }
776         else {
777                 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
778                         DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
779                         get_register_force_spilling (cfg, bb, last, ins, cfg->rs->isymbolic [hreg], bank);
780                         mono_regstate_free_int (cfg->rs, hreg);
781                 }
782         }
783 }
784
785 static MonoInst*
786 create_copy_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, int dest, int src, MonoInst *ins, const unsigned char *ip, int bank)
787 {
788         MonoInst *copy;
789
790         MONO_INST_NEW (cfg, copy, regbank_move_ops [bank]);
791
792         copy->dreg = dest;
793         copy->sreg1 = src;
794         copy->cil_code = ip;
795         if (ins) {
796                 mono_bblock_insert_after_ins (bb, ins, copy);
797                 *last = copy;
798         }
799         DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src, bank), mono_regname_full (dest, bank)));
800         return copy;
801 }
802
803 static MonoInst*
804 create_spilled_store (MonoCompile *cfg, MonoBasicBlock *bb, int spill, int reg, int prev_reg, MonoInst **last, MonoInst *ins, int bank)
805 {
806         MonoInst *store;
807         MONO_INST_NEW (cfg, store, regbank_store_ops [bank]);
808         store->sreg1 = reg;
809         store->inst_destbasereg = cfg->frame_reg;
810         store->inst_offset = mono_spillvar_offset (cfg, spill, bank);
811         if (ins) {
812                 mono_bblock_insert_after_ins (bb, ins, store);
813                 *last = store;
814         }
815         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, bank)));
816         return store;
817 }
818
819 /* flags used in reginfo->flags */
820 enum {
821         MONO_FP_NEEDS_LOAD_SPILL        = regmask (0),
822         MONO_FP_NEEDS_SPILL                     = regmask (1),
823         MONO_FP_NEEDS_LOAD                      = regmask (2)
824 };
825
826 static inline int
827 alloc_int_reg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
828 {
829         int val;
830
831         if (info && info->preferred_mask) {
832                 val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
833                 if (val >= 0) {
834                         DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
835                         return val;
836                 }
837         }
838
839         val = mono_regstate_alloc_int (cfg->rs, dest_mask);
840         if (val < 0)
841                 val = get_register_spilling (cfg, bb, last, ins, dest_mask, sym_reg, 0);
842
843         return val;
844 }
845
846 static inline int
847 alloc_general_reg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins, regmask_t dest_mask, int sym_reg, int bank)
848 {
849         int val;
850
851         val = mono_regstate_alloc_general (cfg->rs, dest_mask, bank);
852
853         if (val < 0)
854                 val = get_register_spilling (cfg, bb, last, ins, dest_mask, sym_reg, bank);
855
856         return val;
857 }
858
859 static inline int
860 alloc_reg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, int bank)
861 {
862         if (G_UNLIKELY (bank))
863                 return alloc_general_reg (cfg, bb, last, ins, dest_mask, sym_reg, bank);
864         else
865                 return alloc_int_reg (cfg, bb, last, ins, dest_mask, sym_reg, info);
866 }
867
868 static inline void
869 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, int bank)
870 {
871         if (G_UNLIKELY (bank)) {
872                 g_assert (reg >= regbank_size [bank]);
873                 g_assert (hreg < regbank_size [bank]);
874                 g_assert (! is_global_freg (hreg));
875
876                 rs->vassign [reg] = hreg;
877                 rs->symbolic [bank] [hreg] = reg;
878                 rs->free_mask [bank] &= ~ (regmask (hreg));
879         }
880         else {
881                 g_assert (reg >= MONO_MAX_IREGS);
882                 g_assert (hreg < MONO_MAX_IREGS);
883 #ifndef __arm__
884                 /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */
885                 g_assert (! is_global_ireg (hreg));
886 #endif
887
888                 rs->vassign [reg] = hreg;
889                 rs->isymbolic [hreg] = reg;
890                 rs->ifree_mask &= ~ (regmask (hreg));
891         }
892 }
893
894 static inline regmask_t
895 get_callee_mask (const char spec)
896 {
897         if (G_UNLIKELY (reg_bank (spec)))
898                 return regbank_callee_regs [reg_bank (spec)];
899         return MONO_ARCH_CALLEE_REGS;
900 }
901
902 static gint8 desc_to_fixed_reg [256];
903 static gboolean desc_to_fixed_reg_inited = FALSE;
904
905 /*
906  * Local register allocation.
907  * We first scan the list of instructions and we save the liveness info of
908  * each register (when the register is first used, when it's value is set etc.).
909  * We also reverse the list of instructions because assigning registers backwards allows 
910  * for more tricks to be used.
911  */
912 void
913 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
914 {
915         MonoInst *ins, *prev, *last;
916         MonoInst **tmp;
917         MonoRegState *rs = cfg->rs;
918         int i, val, max;
919         RegTrack *reginfo;
920         const char *spec;
921         unsigned char spec_src1, spec_src2, spec_dest;
922         int bank = 0;
923 #if MONO_ARCH_USE_FPSTACK
924         gboolean has_fp = FALSE;
925         int fpstack [8];
926         int sp = 0;
927 #endif
928
929         if (!bb->code)
930                 return;
931
932         if (!desc_to_fixed_reg_inited) {
933                 for (i = 0; i < 256; ++i)
934                         desc_to_fixed_reg [i] = MONO_ARCH_INST_FIXED_REG (i);
935                 desc_to_fixed_reg_inited = TRUE;
936         }
937
938         rs->next_vreg = bb->max_vreg;
939         mono_regstate_assign (rs);
940
941         rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
942         for (i = 0; i < MONO_NUM_REGBANKS; ++i)
943                 rs->free_mask [i] = regbank_callee_regs [i];
944
945         max = rs->next_vreg;
946
947         if (cfg->reginfo && cfg->reginfo_len < max)
948                 cfg->reginfo = NULL;
949
950         reginfo = cfg->reginfo;
951         if (!reginfo) {
952                 cfg->reginfo_len = MAX (1024, max * 2);
953                 reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
954         } 
955         else
956                 g_assert (cfg->reginfo_len >= rs->next_vreg);
957
958         if (cfg->verbose_level > 1) {
959                 /* print_regtrack reads the info of all variables */
960                 memset (cfg->reginfo, 0, cfg->reginfo_len * sizeof (RegTrack));
961         }
962
963         if (cfg->new_ir) {
964                 /* 
965                  * For large methods, next_vreg can be very large, so g_malloc0 time can
966                  * be prohibitive. So we manually init the reginfo entries used by the 
967                  * bblock.
968                  */
969                 for (ins = bb->code; ins; ins = ins->next) {
970                         spec = ins_get_spec (ins->opcode);
971
972                         if ((ins->dreg != -1) && (ins->dreg < max)) {
973                                 memset (&reginfo [ins->dreg], 0, sizeof (RegTrack));
974 #if SIZEOF_VOID_P == 4
975                                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
976                                         /**
977                                          * In the new IR, the two vregs of the regpair do not alias the
978                                          * original long vreg. shift the vreg here so the rest of the 
979                                          * allocator doesn't have to care about it.
980                                          */
981                                         if (cfg->new_ir)
982                                                 ins->dreg ++;
983                                         memset (&reginfo [ins->dreg + 1], 0, sizeof (RegTrack));
984                                 }
985 #endif
986                         }
987                         if ((ins->sreg1 != -1) && (ins->sreg1 < max)) {
988                                 memset (&reginfo [ins->sreg1], 0, sizeof (RegTrack));
989 #if SIZEOF_VOID_P == 4
990                                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
991                                         if (cfg->new_ir)
992                                                 ins->sreg1 ++;
993                                         memset (&reginfo [ins->sreg1 + 1], 0, sizeof (RegTrack));
994                                 }
995 #endif
996                         }
997                         if ((ins->sreg2 != -1) && (ins->sreg2 < max)) {
998                                 memset (&reginfo [ins->sreg2], 0, sizeof (RegTrack));
999 #if SIZEOF_VOID_P == 4
1000                                 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
1001                                         if (cfg->new_ir)
1002                                                 ins->sreg2 ++;
1003                                         memset (&reginfo [ins->sreg2 + 1], 0, sizeof (RegTrack));
1004                                 }
1005 #endif
1006                         }
1007                 }
1008         }
1009         else {
1010                 memset (reginfo, 0, max * sizeof (RegTrack));
1011         }
1012
1013         /*if (cfg->opt & MONO_OPT_COPYPROP)
1014                 local_copy_prop (cfg, ins);*/
1015
1016         i = 1;
1017         DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK %d:\n", bb->block_num));
1018         /* forward pass on the instructions to collect register liveness info */
1019         MONO_BB_FOR_EACH_INS (bb, ins) {
1020                 spec = ins_get_spec (ins->opcode);
1021                 spec_src1 = spec [MONO_INST_SRC1];
1022                 spec_src2 = spec [MONO_INST_SRC2];
1023                 spec_dest = spec [MONO_INST_DEST];
1024
1025                 if (G_UNLIKELY (spec == MONO_ARCH_CPU_SPEC)) {
1026                         g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
1027                 }
1028                 
1029                 DEBUG (mono_print_ins_index (i, ins));
1030
1031 #if MONO_ARCH_USE_FPSTACK
1032                 if (sreg1_is_fp (spec) || sreg2_is_fp (spec) || dreg_is_fp (spec))
1033                         has_fp = TRUE;
1034 #endif
1035
1036                 if (spec_src1) {
1037                         bank = sreg1_bank (spec);
1038                         g_assert (ins->sreg1 != -1);
1039                         if (cfg->new_ir && is_soft_reg (ins->sreg1, bank))
1040                                 /* This means the vreg is not local to this bb */
1041                                 g_assert (reginfo [ins->sreg1].born_in > 0);
1042                         rs->vassign [ins->sreg1] = -1;
1043                         //reginfo [ins->sreg1].prev_use = reginfo [ins->sreg1].last_use;
1044                         //reginfo [ins->sreg1].last_use = i;
1045                         if (MONO_ARCH_INST_IS_REGPAIR (spec_src2)) {
1046                                 /* The virtual register is allocated sequentially */
1047                                 rs->vassign [ins->sreg1 + 1] = -1;
1048                                 //reginfo [ins->sreg1 + 1].prev_use = reginfo [ins->sreg1 + 1].last_use;
1049                                 //reginfo [ins->sreg1 + 1].last_use = i;
1050                                 if (reginfo [ins->sreg1 + 1].born_in == 0 || reginfo [ins->sreg1 + 1].born_in > i)
1051                                         reginfo [ins->sreg1 + 1].born_in = i;
1052                         }
1053                 } else {
1054                         ins->sreg1 = -1;
1055                 }
1056                 if (spec_src2) {
1057                         bank = sreg2_bank (spec);
1058                         g_assert (ins->sreg2 != -1);
1059                         if (cfg->new_ir && is_soft_reg (ins->sreg2, bank))
1060                                 /* This means the vreg is not local to this bb */
1061                                 g_assert (reginfo [ins->sreg2].born_in > 0);
1062                         rs->vassign [ins->sreg2] = -1;
1063                         //reginfo [ins->sreg2].prev_use = reginfo [ins->sreg2].last_use;
1064                         //reginfo [ins->sreg2].last_use = i;
1065                         if (MONO_ARCH_INST_IS_REGPAIR (spec_src2)) {
1066                                 /* The virtual register is allocated sequentially */
1067                                 rs->vassign [ins->sreg2 + 1] = -1;
1068                                 //reginfo [ins->sreg2 + 1].prev_use = reginfo [ins->sreg2 + 1].last_use;
1069                                 //reginfo [ins->sreg2 + 1].last_use = i;
1070                                 if (reginfo [ins->sreg2 + 1].born_in == 0 || reginfo [ins->sreg2 + 1].born_in > i)
1071                                         reginfo [ins->sreg2 + 1].born_in = i;
1072                         }
1073                 } else {
1074                         ins->sreg2 = -1;
1075                 }
1076                 if (spec_dest) {
1077                         int dest_dreg;
1078
1079                         bank = dreg_bank (spec);
1080                         if (spec_dest != 'b') /* it's not just a base register */
1081                                 reginfo [ins->dreg].killed_in = i;
1082                         g_assert (ins->dreg != -1);
1083                         rs->vassign [ins->dreg] = -1;
1084                         //reginfo [ins->dreg].prev_use = reginfo [ins->dreg].last_use;
1085                         //reginfo [ins->dreg].last_use = i;
1086                         if (reginfo [ins->dreg].born_in == 0 || reginfo [ins->dreg].born_in > i)
1087                                 reginfo [ins->dreg].born_in = i;
1088
1089                         dest_dreg = desc_to_fixed_reg [spec_dest];
1090                         if (dest_dreg != -1)
1091                                 reginfo [ins->dreg].preferred_mask = (regmask (dest_dreg));
1092
1093 #ifdef MONO_ARCH_INST_FIXED_MASK
1094                         reginfo [ins->dreg].preferred_mask |= MONO_ARCH_INST_FIXED_MASK (spec_dest);
1095 #endif
1096
1097                         if (MONO_ARCH_INST_IS_REGPAIR (spec_dest)) {
1098                                 /* The virtual register is allocated sequentially */
1099                                 rs->vassign [ins->dreg + 1] = -1;
1100                                 //reginfo [ins->dreg + 1].prev_use = reginfo [ins->dreg + 1].last_use;
1101                                 //reginfo [ins->dreg + 1].last_use = i;
1102                                 if (reginfo [ins->dreg + 1].born_in == 0 || reginfo [ins->dreg + 1].born_in > i)
1103                                         reginfo [ins->dreg + 1].born_in = i;
1104                                 if (MONO_ARCH_INST_REGPAIR_REG2 (spec_dest, -1) != -1)
1105                                         reginfo [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec_dest, -1);
1106                         }
1107                 } else {
1108                         ins->dreg = -1;
1109                 }
1110
1111                 if (spec [MONO_INST_CLOB] == 'c') {
1112                         /* A call instruction implicitly uses all registers in call->out_ireg_args */
1113
1114                         MonoCallInst *call = (MonoCallInst*)ins;
1115                         GSList *list;
1116
1117                         list = call->out_ireg_args;
1118                         if (list) {
1119                                 while (list) {
1120                                         guint32 regpair;
1121                                         int reg, hreg;
1122
1123                                         regpair = (guint32)(gssize)(list->data);
1124                                         hreg = regpair >> 24;
1125                                         reg = regpair & 0xffffff;
1126
1127                                         //reginfo [reg].prev_use = reginfo [reg].last_use;
1128                                         //reginfo [reg].last_use = i;
1129
1130                                         list = g_slist_next (list);
1131                                 }
1132                         }
1133
1134                         list = call->out_freg_args;
1135                         if (list) {
1136                                 while (list) {
1137                                         guint32 regpair;
1138                                         int reg, hreg;
1139
1140                                         regpair = (guint32)(gssize)(list->data);
1141                                         hreg = regpair >> 24;
1142                                         reg = regpair & 0xffffff;
1143
1144                                         list = g_slist_next (list);
1145                                 }
1146                         }
1147                 }
1148
1149                 ++i;
1150         }
1151
1152         tmp = &last;
1153
1154         DEBUG (print_regtrack (reginfo, rs->next_vreg));
1155         MONO_BB_FOR_EACH_INS_REVERSE_SAFE (bb, prev, ins) {
1156                 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
1157                 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
1158                 int dreg_high, sreg1_high;
1159                 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
1160                 regmask_t dreg_fixed_mask, sreg1_fixed_mask, sreg2_fixed_mask;
1161                 const unsigned char *ip;
1162                 --i;
1163                 spec = ins_get_spec (ins->opcode);
1164                 spec_src1 = spec [MONO_INST_SRC1];
1165                 spec_src2 = spec [MONO_INST_SRC2];
1166                 spec_dest = spec [MONO_INST_DEST];
1167                 prev_dreg = -1;
1168                 prev_sreg2 = -1;
1169                 clob_dreg = -1;
1170                 clob_reg = -1;
1171                 dest_dreg = -1;
1172                 dest_sreg1 = -1;
1173                 dest_sreg2 = -1;
1174                 prev_sreg1 = -1;
1175                 dreg_high = -1;
1176                 sreg1_high = -1;
1177                 dreg_mask = get_callee_mask (spec_dest);
1178                 sreg1_mask = get_callee_mask (spec_src1);
1179                 sreg2_mask = get_callee_mask (spec_src2);
1180
1181                 DEBUG (printf ("processing:"));
1182                 DEBUG (mono_print_ins_index (i, ins));
1183
1184                 ip = ins->cil_code;
1185
1186                 last = ins;
1187
1188                 /*
1189                  * FIXED REGS
1190                  */
1191                 dest_sreg1 = desc_to_fixed_reg [spec_src1];
1192                 dest_sreg2 = desc_to_fixed_reg [spec_src2];
1193                 dest_dreg = desc_to_fixed_reg [spec_dest];
1194                 clob_reg = desc_to_fixed_reg [(int)spec [MONO_INST_CLOB]];
1195                 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
1196
1197 #ifdef MONO_ARCH_INST_FIXED_MASK
1198                 sreg1_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec_src1);
1199                 sreg2_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec_src2);
1200                 dreg_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec_dest);
1201 #else
1202                 sreg1_fixed_mask = sreg2_fixed_mask = dreg_fixed_mask = 0;
1203 #endif
1204
1205                 /*
1206                  * TRACK FIXED SREG2
1207                  */
1208                 if (dest_sreg2 != -1) {
1209                         if (rs->ifree_mask & (regmask (dest_sreg2))) {
1210                                 if (is_global_ireg (ins->sreg2)) {
1211                                         /* Argument already in hard reg, need to copy */
1212                                         MonoInst *copy = create_copy_ins (cfg, bb, tmp, dest_sreg2, ins->sreg2, NULL, ip, 0);
1213                                         insert_before_ins (bb, ins, copy);
1214                                 }
1215                                 else {
1216                                         val = rs->vassign [ins->sreg2];
1217                                         if (val == -1) {
1218                                                 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
1219                                                 assign_reg (cfg, rs, ins->sreg2, dest_sreg2, 0);
1220                                         } else if (val < -1) {
1221                                                 /* FIXME: */
1222                                                 g_assert_not_reached ();
1223                                         } else {
1224                                                 /* Argument already in hard reg, need to copy */
1225                                                 MonoInst *copy = create_copy_ins (cfg, bb, tmp, dest_sreg2, val, NULL, ip, 0);
1226                                                 insert_before_ins (bb, ins, copy);
1227                                         }
1228                                 }
1229                         } else {
1230                                 gboolean need_spill = TRUE;
1231                                 gboolean need_assign = TRUE;
1232
1233                                 dreg_mask &= ~ (regmask (dest_sreg2));
1234                                 sreg1_mask &= ~ (regmask (dest_sreg2));
1235
1236                                 /* 
1237                                  * First check if dreg is assigned to dest_sreg2, since we
1238                                  * can't spill a dreg.
1239                                  */
1240                                 val = rs->vassign [ins->dreg];
1241                                 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
1242                                         /* 
1243                                          * the destination register is already assigned to 
1244                                          * dest_sreg2: we need to allocate another register for it 
1245                                          * and then copy from this to dest_sreg2.
1246                                          */
1247                                         int new_dest;
1248                                         new_dest = alloc_int_reg (cfg, bb, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg]);
1249                                         g_assert (new_dest >= 0);
1250                                         DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
1251
1252                                         prev_dreg = ins->dreg;
1253                                         assign_reg (cfg, rs, ins->dreg, new_dest, 0);
1254                                         clob_dreg = ins->dreg;
1255                                         create_copy_ins (cfg, bb, tmp, dest_sreg2, new_dest, ins, ip, 0);
1256                                         mono_regstate_free_int (rs, dest_sreg2);
1257                                         need_spill = FALSE;
1258                                 }
1259
1260                                 if (is_global_ireg (ins->sreg2)) {
1261                                         MonoInst *copy = create_copy_ins (cfg, bb, tmp, dest_sreg2, ins->sreg2, NULL, ip, 0);
1262                                         insert_before_ins (bb, ins, copy);
1263                                         need_assign = FALSE;
1264                                 }
1265                                 else {
1266                                         val = rs->vassign [ins->sreg2];
1267                                         if (val == dest_sreg2) {
1268                                                 /* sreg2 is already assigned to the correct register */
1269                                                 need_spill = FALSE;
1270                                         } else if (val < -1) {
1271                                                 /* sreg2 is spilled, it can be assigned to dest_sreg2 */
1272                                         } else if (val >= 0) {
1273                                                 /* sreg2 already assigned to another register */
1274                                                 /*
1275                                                  * We couldn't emit a copy from val to dest_sreg2, because
1276                                                  * val might be spilled later while processing this 
1277                                                  * instruction. So we spill sreg2 so it can be allocated to
1278                                                  * dest_sreg2.
1279                                                  */
1280                                                 DEBUG (printf ("\tforced spill of R%d\n", ins->sreg2));
1281                                                 free_up_reg (cfg, bb, tmp, ins, val, 0);
1282                                         }
1283                                 }
1284
1285                                 if (need_spill) {
1286                                         DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1287                                         free_up_reg (cfg, bb, tmp, ins, dest_sreg2, 0);
1288                                 }
1289
1290                                 if (need_assign) {
1291                                         if (rs->vassign [ins->sreg2] < -1) {
1292                                                 MonoInst *store;
1293                                                 int spill;
1294
1295                                                 /* Need to emit a spill store */
1296                                                 spill = - rs->vassign [ins->sreg2] - 1;
1297                                                 store = create_spilled_store (cfg, bb, spill, dest_sreg2, ins->sreg2, tmp, NULL, bank);                                         
1298                                                 insert_before_ins (bb, ins, store);
1299                                         }
1300                                         /* force-set sreg2 */
1301                                         assign_reg (cfg, rs, ins->sreg2, dest_sreg2, 0);
1302                                 }
1303                         }
1304                         ins->sreg2 = dest_sreg2;
1305                 }
1306
1307                 /*
1308                  * TRACK DREG
1309                  */
1310                 bank = dreg_bank (spec);
1311                 if (spec_dest && is_soft_reg (ins->dreg, bank)) {
1312                         prev_dreg = ins->dreg;
1313                 }
1314
1315                 if (spec_dest == 'b') {
1316                         /* 
1317                          * The dest reg is read by the instruction, not written, so
1318                          * avoid allocating sreg1/sreg2 to the same reg.
1319                          */
1320                         if (!dest_sreg1 != -1)
1321                                 dreg_mask &= ~ (regmask (dest_sreg1));
1322                         if (dest_sreg2 != -1)
1323                                 dreg_mask &= ~ (regmask (dest_sreg2));
1324
1325                         val = rs->vassign [ins->dreg];
1326                         if (is_soft_reg (ins->dreg, bank) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
1327                                 /* DREG is already allocated to a register needed for sreg1 */
1328                                 get_register_force_spilling (cfg, bb, tmp, ins, ins->dreg, 0);
1329                                 mono_regstate_free_int (rs, val);
1330                         }
1331                 }
1332
1333                 /*
1334                  * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1335                  * various complex situations.
1336                  */
1337                 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest)) {
1338                         guint32 dreg2, dest_dreg2;
1339
1340                         g_assert (is_soft_reg (ins->dreg, bank));
1341
1342                         if (dest_dreg != -1) {
1343                                 if (rs->vassign [ins->dreg] != dest_dreg)
1344                                         free_up_reg (cfg, bb, tmp, ins, dest_dreg, 0);
1345
1346                                 dreg2 = ins->dreg + 1;
1347                                 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec_dest, dest_dreg);
1348                                 if (dest_dreg2 != -1) {
1349                                         if (rs->vassign [dreg2] != dest_dreg2)
1350                                                 free_up_reg (cfg, bb, tmp, ins, dest_dreg2, 0);
1351                                 }
1352                         }
1353                 }
1354
1355                 if (dreg_fixed_mask) {
1356                         g_assert (!bank);
1357                         if (is_global_ireg (ins->dreg)) {
1358                                 /* 
1359                                  * The argument is already in a hard reg, but that reg is
1360                                  * not usable by this instruction, so allocate a new one.
1361                                  */
1362                                 val = mono_regstate_alloc_int (rs, dreg_fixed_mask);
1363                                 if (val < 0)
1364                                         val = get_register_spilling (cfg, bb, tmp, ins, dreg_fixed_mask, -1, bank);
1365                                 mono_regstate_free_int (rs, val);
1366                                 dest_dreg = val;
1367
1368                                 /* Fall through */
1369                         }
1370                         else
1371                                 dreg_mask &= dreg_fixed_mask;
1372                 }
1373
1374                 if (is_soft_reg (ins->dreg, bank)) {
1375                         val = rs->vassign [ins->dreg];
1376
1377                         if (val < 0) {
1378                                 int spill = 0;
1379                                 if (val < -1) {
1380                                         /* the register gets spilled after this inst */
1381                                         spill = -val -1;
1382                                 }
1383                                 val = alloc_reg (cfg, bb, tmp, ins, dreg_mask, ins->dreg, &reginfo [ins->dreg], bank);
1384                                 assign_reg (cfg, rs, ins->dreg, val, bank);
1385                                 if (spill)
1386                                         create_spilled_store (cfg, bb, spill, val, prev_dreg, tmp, ins, bank);
1387                         }
1388
1389                         DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, bank), ins->dreg));
1390                         ins->dreg = val;
1391                 }
1392
1393                 /* Handle regpairs */
1394                 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest)) {
1395                         int reg2 = prev_dreg + 1;
1396
1397                         g_assert (!bank);
1398                         g_assert (prev_dreg > -1);
1399                         g_assert (!is_global_ireg (rs->vassign [prev_dreg]));
1400                         mask = regpair_reg2_mask (spec_dest, rs->vassign [prev_dreg]);
1401 #ifdef __i386__
1402                         /* bug #80489 */
1403                         mask &= ~regmask (X86_ECX);
1404 #endif
1405                         val = rs->vassign [reg2];
1406                         if (val < 0) {
1407                                 int spill = 0;
1408                                 if (val < -1) {
1409                                         /* the register gets spilled after this inst */
1410                                         spill = -val -1;
1411                                 }
1412                                 val = mono_regstate_alloc_int (rs, mask);
1413                                 if (val < 0)
1414                                         val = get_register_spilling (cfg, bb, tmp, ins, mask, reg2, bank);
1415                                 if (spill)
1416                                         create_spilled_store (cfg, bb, spill, val, reg2, tmp, ins, bank);
1417                         }
1418                         else {
1419                                 if (! (mask & (regmask (val)))) {
1420                                         val = mono_regstate_alloc_int (rs, mask);
1421                                         if (val < 0)
1422                                                 val = get_register_spilling (cfg, bb, tmp, ins, mask, reg2, bank);
1423
1424                                         /* Reallocate hreg to the correct register */
1425                                         create_copy_ins (cfg, bb, tmp, rs->vassign [reg2], val, ins, ip, bank);
1426
1427                                         mono_regstate_free_int (rs, rs->vassign [reg2]);
1428                                 }
1429                         }                                       
1430
1431                         DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1432                         assign_reg (cfg, rs, reg2, val, bank);
1433
1434                         dreg_high = val;
1435                         ins->backend.reg3 = val;
1436
1437                         if (reg_is_freeable (val, bank) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1438                                 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1439                                 mono_regstate_free_int (rs, val);
1440                         }
1441                 }
1442
1443                 if (prev_dreg >= 0 && is_soft_reg (prev_dreg, bank) && (spec_dest != 'b') && (cfg->new_ir || reginfo [prev_dreg].born_in >= i)) {
1444                         /* 
1445                          * In theory, we could free up the hreg even if the vreg is alive,
1446                          * but branches inside bblocks force us to assign the same hreg
1447                          * to a vreg every time it is encountered.
1448                          */
1449                         int dreg = rs->vassign [prev_dreg];
1450                         g_assert (dreg >= 0);
1451                         DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, bank), prev_dreg, reginfo [prev_dreg].born_in));
1452                         if (G_UNLIKELY (bank))
1453                                 mono_regstate_free_general (rs, dreg, bank);
1454                         else
1455                                 mono_regstate_free_int (rs, dreg);
1456                         if (cfg->new_ir)
1457                                 rs->vassign [prev_dreg] = -1;
1458                 }
1459
1460                 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1461                         /* this instruction only outputs to dest_dreg, need to copy */
1462                         create_copy_ins (cfg, bb, tmp, ins->dreg, dest_dreg, ins, ip, bank);
1463                         ins->dreg = dest_dreg;
1464
1465                         if (G_UNLIKELY (bank)) {
1466                                 if (rs->symbolic [bank] [dest_dreg] >= regbank_size [bank])
1467                                         free_up_reg (cfg, bb, tmp, ins, dest_dreg, bank);
1468                         }
1469                         else {
1470                                 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1471                                         free_up_reg (cfg, bb, tmp, ins, dest_dreg, bank);
1472                         }
1473                 }
1474
1475                 if (spec_dest == 'b') {
1476                         /* 
1477                          * The dest reg is read by the instruction, not written, so
1478                          * avoid allocating sreg1/sreg2 to the same reg.
1479                          */
1480                         if (!sreg1_bank (spec))
1481                                 sreg1_mask &= ~ (regmask (ins->dreg));
1482                         if (!sreg2_bank (spec))
1483                                 sreg2_mask &= ~ (regmask (ins->dreg));
1484                 }
1485
1486                 /*
1487                  * TRACK CLOBBERING
1488                  */
1489                 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1490                         DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1491                         get_register_force_spilling (cfg, bb, tmp, ins, rs->isymbolic [clob_reg], 0);
1492                         mono_regstate_free_int (rs, clob_reg);
1493                 }
1494
1495                 if (spec [MONO_INST_CLOB] == 'c') {
1496                         int j, s, dreg, dreg2, cur_bank;
1497                         guint64 clob_mask;
1498
1499                         clob_mask = MONO_ARCH_CALLEE_REGS;
1500
1501                         if (rs->ifree_mask != MONO_ARCH_CALLEE_REGS) {
1502                                 /*
1503                                  * Need to avoid spilling the dreg since the dreg is not really
1504                                  * clobbered by the call.
1505                                  */
1506                                 if ((prev_dreg != -1) && !reg_bank (spec_dest))
1507                                         dreg = rs->vassign [prev_dreg];
1508                                 else
1509                                         dreg = -1;
1510
1511                                 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest))
1512                                         dreg2 = rs->vassign [prev_dreg + 1];
1513                                 else
1514                                         dreg2 = -1;
1515
1516                                 for (j = 0; j < MONO_MAX_IREGS; ++j) {
1517                                         s = regmask (j);
1518                                         if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1)) {
1519                                                 if ((j != dreg) && (j != dreg2))
1520                                                         get_register_force_spilling (cfg, bb, tmp, ins, rs->isymbolic [j], 0);
1521                                                 else if (rs->isymbolic [j])
1522                                                         /* The hreg is assigned to the dreg of this instruction */
1523                                                         rs->vassign [rs->isymbolic [j]] = -1;
1524                                                 mono_regstate_free_int (rs, j);
1525                                         }
1526                                 }
1527                         }
1528
1529                         for (cur_bank = 1; cur_bank < MONO_NUM_REGBANKS; ++ cur_bank) {
1530                                 if (rs->free_mask [cur_bank] != regbank_callee_regs [cur_bank]) {
1531                                         clob_mask = regbank_callee_regs [cur_bank];
1532                                         if ((prev_dreg != -1) && reg_bank (spec_dest))
1533                                                 dreg = rs->vassign [prev_dreg];
1534                                         else
1535                                                 dreg = -1;
1536
1537                                         for (j = 0; j < regbank_size [cur_bank]; ++j) {
1538                                                 s = regmask (j);
1539                                                 if ((clob_mask & s) && !(rs->free_mask [cur_bank] & s) && (j != ins->sreg1)) {
1540                                                         if (j != dreg)
1541                                                                 get_register_force_spilling (cfg, bb, tmp, ins, rs->symbolic [cur_bank] [j], cur_bank);
1542                                                         else if (rs->symbolic [cur_bank] [j])
1543                                                                 /* The hreg is assigned to the dreg of this instruction */
1544                                                                 rs->vassign [rs->symbolic [cur_bank] [j]] = -1;
1545                                                         mono_regstate_free_general (rs, j, cur_bank);
1546                                                 }
1547                                         }
1548                                 }
1549                         }
1550                 }
1551
1552                 /*
1553                  * TRACK ARGUMENT REGS
1554                  */
1555                 if (spec [MONO_INST_CLOB] == 'c') {
1556                         MonoCallInst *call = (MonoCallInst*)ins;
1557                         GSList *list;
1558
1559                         /* 
1560                          * This needs to be done before assigning sreg1, so sreg1 will
1561                          * not be assigned one of the argument regs.
1562                          */
1563
1564                         /* 
1565                          * Assign all registers in call->out_reg_args to the proper 
1566                          * argument registers.
1567                          */
1568
1569                         list = call->out_ireg_args;
1570                         if (list) {
1571                                 while (list) {
1572                                         guint32 regpair;
1573                                         int reg, hreg;
1574
1575                                         regpair = (guint32)(gssize)(list->data);
1576                                         hreg = regpair >> 24;
1577                                         reg = regpair & 0xffffff;
1578
1579                                         assign_reg (cfg, rs, reg, hreg, 0);
1580
1581                                         sreg1_mask &= ~(regmask (hreg));
1582
1583                                         DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1584
1585                                         list = g_slist_next (list);
1586                                 }
1587                         }
1588
1589                         list = call->out_freg_args;
1590                         if (list) {
1591                                 while (list) {
1592                                         guint32 regpair;
1593                                         int reg, hreg;
1594
1595                                         regpair = (guint32)(gssize)(list->data);
1596                                         hreg = regpair >> 24;
1597                                         reg = regpair & 0xffffff;
1598
1599                                         assign_reg (cfg, rs, reg, hreg, 1);
1600
1601                                         DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_regname_full (hreg, 1), reg));
1602
1603                                         list = g_slist_next (list);
1604                                 }
1605                         }
1606                 }
1607
1608                 /*
1609                  * TRACK SREG1
1610                  */
1611                 bank = sreg1_bank (spec);
1612                 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest) && (spec [MONO_INST_CLOB] == '1')) {
1613                         g_assert (is_soft_reg (ins->sreg1, bank));
1614
1615                         /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1616                         if (dest_sreg1 != -1)
1617                                 g_assert (dest_sreg1 == ins->dreg);
1618                         val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
1619                         g_assert (val >= 0);
1620
1621                         if (rs->vassign [ins->sreg1] >= 0 && rs->vassign [ins->sreg1] != val)
1622                                 // FIXME:
1623                                 g_assert_not_reached ();
1624
1625                         assign_reg (cfg, rs, ins->sreg1, val, bank);
1626
1627                         DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, bank), ins->sreg1));
1628
1629                         g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec_src1, ins->dreg));
1630                         val = mono_regstate_alloc_int (rs, regmask (dreg_high));
1631                         g_assert (val >= 0);
1632
1633                         if (rs->vassign [ins->sreg1 + 1] >= 0 && rs->vassign [ins->sreg1 + 1] != val)
1634                                 // FIXME:
1635                                 g_assert_not_reached ();
1636
1637                         assign_reg (cfg, rs, ins->sreg1 + 1, val, bank);
1638
1639                         DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, bank), ins->sreg1 + 1));
1640
1641                         /* Skip rest of this section */
1642                         dest_sreg1 = -1;
1643                 }
1644
1645                 if (sreg1_fixed_mask) {
1646                         g_assert (!bank);
1647                         if (is_global_ireg (ins->sreg1)) {
1648                                 /* 
1649                                  * The argument is already in a hard reg, but that reg is
1650                                  * not usable by this instruction, so allocate a new one.
1651                                  */
1652                                 val = mono_regstate_alloc_int (rs, sreg1_fixed_mask);
1653                                 if (val < 0)
1654                                         val = get_register_spilling (cfg, bb, tmp, ins, sreg1_fixed_mask, -1, bank);
1655                                 mono_regstate_free_int (rs, val);
1656                                 dest_sreg1 = val;
1657
1658                                 /* Fall through to the dest_sreg1 != -1 case */
1659                         }
1660                         else
1661                                 sreg1_mask &= sreg1_fixed_mask;
1662                 }
1663
1664                 if (dest_sreg1 != -1) {
1665                         sreg1_mask = regmask (dest_sreg1);
1666
1667                         if ((rs->vassign [ins->sreg1] != dest_sreg1) && !(rs->ifree_mask & (regmask (dest_sreg1)))) {
1668                                 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1669                                 get_register_force_spilling (cfg, bb, tmp, ins, rs->isymbolic [dest_sreg1], 0);
1670                                 mono_regstate_free_int (rs, dest_sreg1);
1671                         }
1672                         if (is_global_ireg (ins->sreg1)) {
1673                                 /* The argument is already in a hard reg, need to copy */
1674                                 MonoInst *copy = create_copy_ins (cfg, bb, tmp, dest_sreg1, ins->sreg1, NULL, ip, 0);
1675                                 insert_before_ins (bb, ins, copy);
1676                                 ins->sreg1 = dest_sreg1;
1677                         }
1678                 }
1679
1680                 if (is_soft_reg (ins->sreg1, bank)) {
1681                         val = rs->vassign [ins->sreg1];
1682                         prev_sreg1 = ins->sreg1;
1683                         if (val < 0) {
1684                                 int spill = 0;
1685                                 if (val < -1) {
1686                                         /* the register gets spilled after this inst */
1687                                         spill = -val -1;
1688                                 }
1689
1690                                 if ((ins->opcode == OP_MOVE) && !spill && !bank && is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg)))) {
1691                                         /* 
1692                                          * Allocate the same hreg to sreg1 as well so the 
1693                                          * peephole can get rid of the move.
1694                                          */
1695                                         sreg1_mask = regmask (ins->dreg);
1696                                 }
1697
1698                                 if (spec [MONO_INST_CLOB] == '1' && !dreg_bank (spec) && (rs->ifree_mask & (regmask (ins->dreg))))
1699                                         /* Allocate the same reg to sreg1 to avoid a copy later */
1700                                         sreg1_mask = regmask (ins->dreg);
1701
1702                                 val = alloc_reg (cfg, bb, tmp, ins, sreg1_mask, ins->sreg1, &reginfo [ins->sreg1], bank);
1703                                 assign_reg (cfg, rs, ins->sreg1, val, bank);
1704                                 DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, bank), ins->sreg1));
1705
1706                                 if (spill) {
1707                                         MonoInst *store = create_spilled_store (cfg, bb, spill, val, prev_sreg1, tmp, NULL, bank);
1708                                         /*
1709                                          * Need to insert before the instruction since it can
1710                                          * overwrite sreg1.
1711                                          */
1712                                         insert_before_ins (bb, ins, store);
1713                                 }
1714                         }
1715                         else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1716                                 MonoInst *copy = create_copy_ins (cfg, bb, tmp, dest_sreg1, val, NULL, ip, bank);
1717                                 insert_before_ins (bb, ins, copy);
1718                                 sreg2_mask &= ~(regmask (dest_sreg1));
1719                                 val = dest_sreg1;
1720                         }
1721                                 
1722                         ins->sreg1 = val;
1723                 }
1724                 else {
1725                         prev_sreg1 = -1;
1726                 }
1727                 sreg2_mask &= ~(regmask (ins->sreg1));
1728
1729                 /* Handle the case when sreg1 is a regpair but dreg is not */
1730                 if (MONO_ARCH_INST_IS_REGPAIR (spec_src1) && (spec [MONO_INST_CLOB] != '1')) {
1731                         int reg2 = prev_sreg1 + 1;
1732
1733                         g_assert (!bank);
1734                         g_assert (prev_sreg1 > -1);
1735                         g_assert (!is_global_ireg (rs->vassign [prev_sreg1]));
1736                         mask = regpair_reg2_mask (spec_src1, rs->vassign [prev_sreg1]);
1737                         val = rs->vassign [reg2];
1738                         if (val < 0) {
1739                                 int spill = 0;
1740                                 if (val < -1) {
1741                                         /* the register gets spilled after this inst */
1742                                         spill = -val -1;
1743                                 }
1744                                 val = mono_regstate_alloc_int (rs, mask);
1745                                 if (val < 0)
1746                                         val = get_register_spilling (cfg, bb, tmp, ins, mask, reg2, bank);
1747                                 if (spill)
1748                                         g_assert_not_reached ();
1749                         }
1750                         else {
1751                                 if (! (mask & (regmask (val)))) {
1752                                         /* The vreg is already allocated to a wrong hreg */
1753                                         /* FIXME: */
1754                                         g_assert_not_reached ();
1755 #if 0
1756                                         val = mono_regstate_alloc_int (rs, mask);
1757                                         if (val < 0)
1758                                                 val = get_register_spilling (cfg, bb, tmp, ins, mask, reg2, bank);
1759
1760                                         /* Reallocate hreg to the correct register */
1761                                         create_copy_ins (cfg, bb, tmp, rs->vassign [reg2], val, ins, ip, bank);
1762
1763                                         mono_regstate_free_int (rs, rs->vassign [reg2]);
1764 #endif
1765                                 }
1766                         }                                       
1767
1768                         sreg1_high = val;
1769                         DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1770                         assign_reg (cfg, rs, reg2, val, bank);
1771                 }
1772
1773                 /* Handle dreg==sreg1 */
1774                 if (((dreg_is_fp (spec) && sreg1_is_fp (spec)) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1775                         MonoInst *sreg2_copy = NULL;
1776                         MonoInst *copy;
1777                         int bank = reg_bank (spec_src1);
1778
1779                         if (ins->dreg == ins->sreg2) {
1780                                 /* 
1781                                  * copying sreg1 to dreg could clobber sreg2, so allocate a new
1782                                  * register for it.
1783                                  */
1784                                 int reg2 = alloc_reg (cfg, bb, tmp, ins, dreg_mask, ins->sreg2, NULL, bank);
1785
1786                                 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, bank), mono_regname_full (reg2, bank)));
1787                                 sreg2_copy = create_copy_ins (cfg, bb, tmp, reg2, ins->sreg2, NULL, ip, bank);
1788                                 prev_sreg2 = ins->sreg2 = reg2;
1789
1790                                 if (G_UNLIKELY (bank))
1791                                         mono_regstate_free_general (rs, reg2, bank);
1792                                 else
1793                                         mono_regstate_free_int (rs, reg2);
1794                         }
1795
1796                         if (MONO_ARCH_INST_IS_REGPAIR (spec_src1)) {
1797                                 /* Copying sreg1_high to dreg could also clobber sreg2 */
1798                                 if (rs->vassign [prev_sreg1 + 1] == ins->sreg2)
1799                                         /* FIXME: */
1800                                         g_assert_not_reached ();
1801
1802                                 /* 
1803                                  * sreg1 and dest are already allocated to the same regpair by the
1804                                  * SREG1 allocation code.
1805                                  */
1806                                 g_assert (ins->sreg1 == ins->dreg);
1807                                 g_assert (dreg_high == sreg1_high);
1808                         }
1809
1810                         DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, bank), mono_regname_full (ins->dreg, bank)));
1811                         copy = create_copy_ins (cfg, bb, tmp, ins->dreg, ins->sreg1, NULL, ip, bank);
1812                         insert_before_ins (bb, ins, copy);
1813
1814                         if (sreg2_copy)
1815                                 insert_before_ins (bb, copy, sreg2_copy);
1816
1817                         /*
1818                          * Need to prevent sreg2 to be allocated to sreg1, since that
1819                          * would screw up the previous copy.
1820                          */
1821                         sreg2_mask &= ~ (regmask (ins->sreg1));
1822                         /* we set sreg1 to dest as well */
1823                         prev_sreg1 = ins->sreg1 = ins->dreg;
1824                         sreg2_mask &= ~ (regmask (ins->dreg));
1825                 }
1826
1827                 /*
1828                  * TRACK SREG2
1829                  */
1830                 bank = sreg2_bank (spec);
1831                 if (MONO_ARCH_INST_IS_REGPAIR (spec_src2))
1832                         g_assert_not_reached ();
1833                 if (is_soft_reg (ins->sreg2, bank)) {
1834                         val = rs->vassign [ins->sreg2];
1835
1836                         if (val < 0) {
1837                                 int spill = 0;
1838                                 if (val < -1) {
1839                                         /* the register gets spilled after this inst */
1840                                         spill = -val -1;
1841                                 }
1842                                 val = alloc_reg (cfg, bb, tmp, ins, sreg2_mask, ins->sreg2, &reginfo [ins->sreg2], bank);
1843                                 assign_reg (cfg, rs, ins->sreg2, val, bank);
1844                                 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, bank), ins->sreg2));
1845                                 if (spill) {
1846                                         MonoInst *store = create_spilled_store (cfg, bb, spill, val, prev_sreg2, tmp, NULL, bank);
1847                                         /*
1848                                          * Need to insert before the instruction since it can
1849                                          * overwrite sreg2.
1850                                          */
1851                                         insert_before_ins (bb, ins, store);
1852                                 }
1853                         }
1854                         ins->sreg2 = val;
1855                 }
1856                 else {
1857                         prev_sreg2 = -1;
1858                 }
1859
1860                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1861                         DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1862                         mono_regstate_free_int (rs, ins->sreg1);
1863                 }
1864                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1865                         DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1866                         mono_regstate_free_int (rs, ins->sreg2);
1867                 }*/
1868         
1869                 DEBUG (mono_print_ins_index (i, ins));
1870         }
1871
1872         // FIXME: Set MAX_FREGS to 8
1873         // FIXME: Optimize generated code
1874 #if MONO_ARCH_USE_FPSTACK
1875         /*
1876          * Make a forward pass over the code, simulating the fp stack, making sure the
1877          * arguments required by the fp opcodes are at the top of the stack.
1878          */
1879         if (has_fp) {
1880                 MonoInst *prev = NULL;
1881                 MonoInst *fxch;
1882                 int tmp;
1883
1884                 for (ins = bb->code; ins; ins = ins->next) {
1885                         spec = ins_get_spec (ins->opcode);
1886
1887                         DEBUG (printf ("processing:"));
1888                         DEBUG (mono_print_ins_index (0, ins));
1889
1890                         if (ins->opcode == OP_FMOVE) {
1891                                 /* Do it by renaming the source to the destination on the stack */
1892                                 // FIXME: Is this correct ?
1893                                 for (i = 0; i < sp; ++i)
1894                                         if (fpstack [i] == ins->sreg1)
1895                                                 fpstack [i] = ins->dreg;
1896                                 prev = ins;
1897                                 continue;
1898                         }
1899
1900                         if (sreg1_is_fp (spec) && sreg2_is_fp (spec) && (fpstack [sp - 2] != ins->sreg1)) {
1901                                 /* Arg1 must be in %st(1) */
1902                                 g_assert (prev);
1903
1904                                 i = 0;
1905                                 while ((i < sp) && (fpstack [i] != ins->sreg1))
1906                                         i ++;
1907                                 g_assert (i < sp);
1908
1909                                 if (sp - 1 - i > 0) {
1910                                         /* First move it to %st(0) */
1911                                         DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i));
1912                                                 
1913                                         MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
1914                                         fxch->inst_imm = sp - 1 - i;
1915
1916                                         prev->next = fxch;
1917                                         fxch->next = ins;
1918                                         prev = fxch;
1919
1920                                         tmp = fpstack [sp - 1];
1921                                         fpstack [sp - 1] = fpstack [i];
1922                                         fpstack [i] = tmp;
1923                                 }
1924                                         
1925                                 /* Then move it to %st(1) */
1926                                 DEBUG (printf ("\tswap %%st(0) and %%st(1)\n"));
1927                                 
1928                                 MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
1929                                 fxch->inst_imm = 1;
1930
1931                                 prev->next = fxch;
1932                                 fxch->next = ins;
1933                                 prev = fxch;
1934
1935                                 tmp = fpstack [sp - 1];
1936                                 fpstack [sp - 1] = fpstack [sp - 2];
1937                                 fpstack [sp - 2] = tmp;
1938                         }
1939
1940                         if (sreg2_is_fp (spec)) {
1941                                 g_assert (sp > 0);
1942
1943                                 if (fpstack [sp - 1] != ins->sreg2) {
1944                                         g_assert (prev);
1945
1946                                         i = 0;
1947                                         while ((i < sp) && (fpstack [i] != ins->sreg2))
1948                                                 i ++;
1949                                         g_assert (i < sp);
1950
1951                                         DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i));
1952
1953                                         MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
1954                                         fxch->inst_imm = sp - 1 - i;
1955
1956                                         prev->next = fxch;
1957                                         fxch->next = ins;
1958                                         prev = fxch;
1959
1960                                         tmp = fpstack [sp - 1];
1961                                         fpstack [sp - 1] = fpstack [i];
1962                                         fpstack [i] = tmp;
1963                                 }
1964
1965                                 sp --;
1966                         }
1967
1968                         if (sreg1_is_fp (spec)) {
1969                                 g_assert (sp > 0);
1970
1971                                 if (fpstack [sp - 1] != ins->sreg1) {
1972                                         g_assert (prev);
1973
1974                                         i = 0;
1975                                         while ((i < sp) && (fpstack [i] != ins->sreg1))
1976                                                 i ++;
1977                                         g_assert (i < sp);
1978
1979                                         DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i));
1980
1981                                         MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
1982                                         fxch->inst_imm = sp - 1 - i;
1983
1984                                         prev->next = fxch;
1985                                         fxch->next = ins;
1986                                         prev = fxch;
1987
1988                                         tmp = fpstack [sp - 1];
1989                                         fpstack [sp - 1] = fpstack [i];
1990                                         fpstack [i] = tmp;
1991                                 }
1992
1993                                 sp --;
1994                         }
1995
1996                         if (dreg_is_fp (spec)) {
1997                                 g_assert (sp < 8);
1998                                 fpstack [sp ++] = ins->dreg;
1999                         }
2000
2001                         if (G_UNLIKELY (cfg->verbose_level >= 2)) {
2002                                 printf ("\t[");
2003                                 for (i = 0; i < sp; ++i)
2004                                         printf ("%s%%fr%d", (i > 0) ? ", " : "", fpstack [i]);
2005                                 printf ("]\n");
2006                         }
2007
2008                         prev = ins;
2009                 }
2010
2011                 if (sp && bb != cfg->bb_exit && !(bb->out_count == 1 && bb->out_bb [0] == cfg->bb_exit)) {
2012                         /* Remove remaining items from the fp stack */
2013                         /* 
2014                          * These can remain for example as a result of a dead fmove like in
2015                          * System.Collections.Generic.EqualityComparer<double>.Equals ().
2016                          */
2017                         while (sp) {
2018                                 MONO_INST_NEW (cfg, ins, OP_X86_FPOP);
2019                                 mono_add_ins_to_end (bb, ins);
2020                                 sp --;
2021                         }
2022                 }
2023         }
2024 #endif
2025 }
2026
2027 CompRelation
2028 mono_opcode_to_cond (int opcode)
2029 {
2030         switch (opcode) {
2031         case CEE_BEQ:
2032         case OP_CEQ:
2033         case OP_IBEQ:
2034         case OP_ICEQ:
2035         case OP_LBEQ:
2036         case OP_LCEQ:
2037         case OP_FBEQ:
2038         case OP_FCEQ:
2039         case OP_COND_EXC_EQ:
2040         case OP_COND_EXC_IEQ:
2041         case OP_CMOV_IEQ:
2042         case OP_CMOV_LEQ:
2043                 return CMP_EQ;
2044         case CEE_BNE_UN:
2045         case OP_IBNE_UN:
2046         case OP_LBNE_UN:
2047         case OP_FBNE_UN:
2048         case OP_COND_EXC_NE_UN:
2049         case OP_COND_EXC_INE_UN:
2050         case OP_CMOV_INE_UN:
2051         case OP_CMOV_LNE_UN:
2052                 return CMP_NE;
2053         case CEE_BLE:
2054         case OP_IBLE:
2055         case OP_LBLE:
2056         case OP_FBLE:
2057         case OP_CMOV_ILE:
2058         case OP_CMOV_LLE:
2059                 return CMP_LE;
2060         case CEE_BGE:
2061         case OP_IBGE:
2062         case OP_LBGE:
2063         case OP_FBGE:
2064         case OP_CMOV_IGE:
2065         case OP_CMOV_LGE:
2066                 return CMP_GE;
2067         case CEE_BLT:
2068         case OP_CLT:
2069         case OP_IBLT:
2070         case OP_ICLT:
2071         case OP_LBLT:
2072         case OP_LCLT:
2073         case OP_FBLT:
2074         case OP_FCLT:
2075         case OP_COND_EXC_LT:
2076         case OP_COND_EXC_ILT:
2077         case OP_CMOV_ILT:
2078         case OP_CMOV_LLT:
2079                 return CMP_LT;
2080         case CEE_BGT:
2081         case OP_CGT:
2082         case OP_IBGT:
2083         case OP_ICGT:
2084         case OP_LBGT:
2085         case OP_LCGT:
2086         case OP_FBGT:
2087         case OP_FCGT:
2088         case OP_COND_EXC_GT:
2089         case OP_COND_EXC_IGT:
2090         case OP_CMOV_IGT:
2091         case OP_CMOV_LGT:
2092                 return CMP_GT;
2093
2094         case CEE_BLE_UN:
2095         case OP_IBLE_UN:
2096         case OP_LBLE_UN:
2097         case OP_FBLE_UN:
2098         case OP_COND_EXC_LE_UN:
2099         case OP_COND_EXC_ILE_UN:
2100         case OP_CMOV_ILE_UN:
2101         case OP_CMOV_LLE_UN:
2102                 return CMP_LE_UN;
2103         case CEE_BGE_UN:
2104         case OP_IBGE_UN:
2105         case OP_LBGE_UN:
2106         case OP_FBGE_UN:
2107         case OP_CMOV_IGE_UN:
2108         case OP_CMOV_LGE_UN:
2109                 return CMP_GE_UN;
2110         case CEE_BLT_UN:
2111         case OP_CLT_UN:
2112         case OP_IBLT_UN:
2113         case OP_ICLT_UN:
2114         case OP_LBLT_UN:
2115         case OP_LCLT_UN:
2116         case OP_FBLT_UN:
2117         case OP_FCLT_UN:
2118         case OP_COND_EXC_LT_UN:
2119         case OP_COND_EXC_ILT_UN:
2120         case OP_CMOV_ILT_UN:
2121         case OP_CMOV_LLT_UN:
2122                 return CMP_LT_UN;
2123         case CEE_BGT_UN:
2124         case OP_CGT_UN:
2125         case OP_IBGT_UN:
2126         case OP_ICGT_UN:
2127         case OP_LBGT_UN:
2128         case OP_LCGT_UN:
2129         case OP_FCGT_UN:
2130         case OP_FBGT_UN:
2131         case OP_COND_EXC_GT_UN:
2132         case OP_COND_EXC_IGT_UN:
2133         case OP_CMOV_IGT_UN:
2134         case OP_CMOV_LGT_UN:
2135                 return CMP_GT_UN;
2136         default:
2137                 printf ("%s\n", mono_inst_name (opcode));
2138                 g_assert_not_reached ();
2139                 return 0;
2140         }
2141 }
2142
2143 CompRelation
2144 mono_negate_cond (CompRelation cond)
2145 {
2146         switch (cond) {
2147         case CMP_EQ:
2148                 return CMP_NE;
2149         case CMP_NE:
2150                 return CMP_EQ;
2151         case CMP_LE:
2152                 return CMP_GT;
2153         case CMP_GE:
2154                 return CMP_LT;
2155         case CMP_LT:
2156                 return CMP_GE;
2157         case CMP_GT:
2158                 return CMP_LE;
2159         case CMP_LE_UN:
2160                 return CMP_GT_UN;
2161         case CMP_GE_UN:
2162                 return CMP_LT_UN;
2163         case CMP_LT_UN:
2164                 return CMP_GE_UN;
2165         case CMP_GT_UN:
2166                 return CMP_LE_UN;
2167         default:
2168                 g_assert_not_reached ();
2169         }
2170 }
2171
2172 CompType
2173 mono_opcode_to_type (int opcode, int cmp_opcode)
2174 {
2175         if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
2176                 return CMP_TYPE_L;
2177         else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
2178                 return CMP_TYPE_L;
2179         else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLT_UN))
2180                 return CMP_TYPE_I;
2181         else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
2182                 return CMP_TYPE_I;
2183         else if ((opcode >= OP_LBEQ) && (opcode <= OP_LBLT_UN))
2184                 return CMP_TYPE_L;
2185         else if ((opcode >= OP_LCEQ) && (opcode <= OP_LCLT_UN))
2186                 return CMP_TYPE_L;
2187         else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLT_UN))
2188                 return CMP_TYPE_F;
2189         else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
2190                 return CMP_TYPE_F;
2191         else if ((opcode >= OP_COND_EXC_IEQ) && (opcode <= OP_COND_EXC_ILT_UN))
2192                 return CMP_TYPE_I;
2193         else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
2194                 switch (cmp_opcode) {
2195                 case OP_ICOMPARE:
2196                 case OP_ICOMPARE_IMM:
2197                 case OP_LCOMPARE_IMM:
2198                         return CMP_TYPE_I;
2199                 default:
2200                         return CMP_TYPE_L;
2201                 }
2202         } else {
2203                 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
2204                 return 0;
2205         }
2206 }
2207
2208 gboolean
2209 mono_is_regsize_var (MonoType *t)
2210 {
2211         if (t->byref)
2212                 return TRUE;
2213         t = mono_type_get_underlying_type (t);
2214         switch (t->type) {
2215         case MONO_TYPE_BOOLEAN:
2216         case MONO_TYPE_CHAR:
2217         case MONO_TYPE_I1:
2218         case MONO_TYPE_U1:
2219         case MONO_TYPE_I2:
2220         case MONO_TYPE_U2:
2221         case MONO_TYPE_I4:
2222         case MONO_TYPE_U4:
2223         case MONO_TYPE_I:
2224         case MONO_TYPE_U:
2225         case MONO_TYPE_PTR:
2226         case MONO_TYPE_FNPTR:
2227 #if SIZEOF_VOID_P == 8
2228         case MONO_TYPE_I8:
2229         case MONO_TYPE_U8:
2230 #endif
2231                 return TRUE;
2232         case MONO_TYPE_OBJECT:
2233         case MONO_TYPE_STRING:
2234         case MONO_TYPE_CLASS:
2235         case MONO_TYPE_SZARRAY:
2236         case MONO_TYPE_ARRAY:
2237                 return TRUE;
2238         case MONO_TYPE_GENERICINST:
2239                 if (!mono_type_generic_inst_is_valuetype (t))
2240                         return TRUE;
2241                 return FALSE;
2242         case MONO_TYPE_VALUETYPE:
2243                 return FALSE;
2244         }
2245         return FALSE;
2246 }
2247
2248 /*
2249  * mono_peephole_ins:
2250  *
2251  *   Perform some architecture independent peephole optimizations.
2252  */
2253 void
2254 mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins)
2255 {
2256         MonoInst *last_ins = ins->prev;
2257
2258         switch (ins->opcode) {
2259         case OP_MUL_IMM: 
2260                 /* remove unnecessary multiplication with 1 */
2261                 if (ins->inst_imm == 1) {
2262                         if (ins->dreg != ins->sreg1)
2263                                 ins->opcode = OP_MOVE;
2264                         else
2265                                 MONO_DELETE_INS (bb, ins);
2266                 }
2267                 break;
2268         case OP_LOAD_MEMBASE:
2269         case OP_LOADI4_MEMBASE:
2270                 /* 
2271                  * Note: if reg1 = reg2 the load op is removed
2272                  *
2273                  * OP_STORE_MEMBASE_REG reg1, offset(basereg) 
2274                  * OP_LOAD_MEMBASE offset(basereg), reg2
2275                  * -->
2276                  * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2277                  * OP_MOVE reg1, reg2
2278                  */
2279                 if (last_ins &&
2280                         (((ins->opcode == OP_LOADI4_MEMBASE) && (last_ins->opcode == OP_STOREI4_MEMBASE_REG)) ||
2281                          ((ins->opcode == OP_LOAD_MEMBASE) && (last_ins->opcode == OP_STORE_MEMBASE_REG))) &&
2282                         ins->inst_basereg == last_ins->inst_destbasereg &&
2283                         ins->inst_offset == last_ins->inst_offset) {
2284                         if (ins->dreg == last_ins->sreg1) {
2285                                 MONO_DELETE_INS (bb, ins);
2286                                 break;
2287                         } else {
2288                                 ins->opcode = OP_MOVE;
2289                                 ins->sreg1 = last_ins->sreg1;
2290                         }
2291                         
2292                         /* 
2293                          * Note: reg1 must be different from the basereg in the second load
2294                          * Note: if reg1 = reg2 is equal then second load is removed
2295                          *
2296                          * OP_LOAD_MEMBASE offset(basereg), reg1
2297                          * OP_LOAD_MEMBASE offset(basereg), reg2
2298                          * -->
2299                          * OP_LOAD_MEMBASE offset(basereg), reg1
2300                          * OP_MOVE reg1, reg2
2301                          */
2302                 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2303                                                    || last_ins->opcode == OP_LOAD_MEMBASE) &&
2304                           ins->inst_basereg != last_ins->dreg &&
2305                           ins->inst_basereg == last_ins->inst_basereg &&
2306                           ins->inst_offset == last_ins->inst_offset) {
2307
2308                         if (ins->dreg == last_ins->dreg) {
2309                                 MONO_DELETE_INS (bb, ins);
2310                         } else {
2311                                 ins->opcode = OP_MOVE;
2312                                 ins->sreg1 = last_ins->dreg;
2313                         }
2314
2315                         //g_assert_not_reached ();
2316
2317 #if 0
2318                         /* 
2319                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2320                          * OP_LOAD_MEMBASE offset(basereg), reg
2321                          * -->
2322                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2323                          * OP_ICONST reg, imm
2324                          */
2325                 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2326                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2327                                    ins->inst_basereg == last_ins->inst_destbasereg &&
2328                                    ins->inst_offset == last_ins->inst_offset) {
2329                         ins->opcode = OP_ICONST;
2330                         ins->inst_c0 = last_ins->inst_imm;
2331                         g_assert_not_reached (); // check this rule
2332 #endif
2333                 }
2334                 break;
2335         case OP_LOADI1_MEMBASE:
2336         case OP_LOADU1_MEMBASE:
2337                 /* 
2338                  * Note: if reg1 = reg2 the load op is removed
2339                  *
2340                  * OP_STORE_MEMBASE_REG reg1, offset(basereg) 
2341                  * OP_LOAD_MEMBASE offset(basereg), reg2
2342                  * -->
2343                  * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2344                  * OP_MOVE reg1, reg2
2345                  */
2346                 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2347                         ins->inst_basereg == last_ins->inst_destbasereg &&
2348                         ins->inst_offset == last_ins->inst_offset) {
2349                         ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_PCONV_TO_I1 : OP_PCONV_TO_U1;
2350                         ins->sreg1 = last_ins->sreg1;
2351                 }
2352                 break;
2353         case OP_LOADI2_MEMBASE:
2354         case OP_LOADU2_MEMBASE:
2355                 /* 
2356                  * Note: if reg1 = reg2 the load op is removed
2357                  *
2358                  * OP_STORE_MEMBASE_REG reg1, offset(basereg) 
2359                  * OP_LOAD_MEMBASE offset(basereg), reg2
2360                  * -->
2361                  * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2362                  * OP_MOVE reg1, reg2
2363                  */
2364                 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2365                         ins->inst_basereg == last_ins->inst_destbasereg &&
2366                         ins->inst_offset == last_ins->inst_offset) {
2367 #if SIZEOF_VOID_P == 8
2368                         ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_PCONV_TO_I2 : OP_PCONV_TO_U2;
2369 #else
2370                         /* The definition of OP_PCONV_TO_U2 is wrong */
2371                         ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_PCONV_TO_I2 : OP_ICONV_TO_U2;
2372 #endif
2373                         ins->sreg1 = last_ins->sreg1;
2374                 }
2375                 break;
2376         case OP_MOVE:
2377         case OP_FMOVE:
2378                 /*
2379                  * Removes:
2380                  *
2381                  * OP_MOVE reg, reg 
2382                  */
2383                 if (ins->dreg == ins->sreg1) {
2384                         MONO_DELETE_INS (bb, ins);
2385                         break;
2386                 }
2387                 /* 
2388                  * Removes:
2389                  *
2390                  * OP_MOVE sreg, dreg 
2391                  * OP_MOVE dreg, sreg
2392                  */
2393                 if (last_ins && last_ins->opcode == OP_MOVE &&
2394                         ins->sreg1 == last_ins->dreg &&
2395                         ins->dreg == last_ins->sreg1) {
2396                         MONO_DELETE_INS (bb, ins);
2397                 }
2398                 break;
2399         case OP_NOP:
2400                 MONO_DELETE_INS (bb, ins);
2401                 break;
2402         }
2403 }
2404