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