2 * mini-codegen.c: Arch independent code generation functionality
4 * (C) 2003 Ximian, Inc.
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>
22 #include "mini-arch.h"
24 #define DEBUG(a) MINI_DEBUG(cfg->verbose_level, 2, a;)
26 #define use_fpstack MONO_ARCH_USE_FPSTACK
29 g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
34 new_list = mono_mempool_alloc (mp, sizeof (GSList));
35 new_list->data = data;
36 new_list->next = NULL;
42 last->next = new_list;
50 * Duplicated here from regalloc.c so they can be inlined
51 * FIXME: Remove the old one after the new JIT is done
55 mono_regstate2_reset (MonoRegState *rs) {
56 rs->next_vreg = MONO_MAX_IREGS;
59 static inline MonoRegState*
60 mono_regstate2_new (void)
62 MonoRegState* rs = g_new0 (MonoRegState, 1);
64 mono_regstate2_reset (rs);
70 mono_regstate2_free (MonoRegState *rs) {
76 mono_regstate_assign (MonoRegState *rs) {
77 if (rs->next_vreg > rs->vassign_size) {
79 rs->vassign_size = MAX (rs->next_vreg, 256);
80 rs->vassign = g_malloc (rs->vassign_size * sizeof (int));
83 memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
84 memset (rs->vassign, -1, sizeof (rs->vassign [0]) * rs->next_vreg);
86 memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
90 mono_regstate_alloc_int (MonoRegState *rs, regmask_t allow)
92 regmask_t mask = allow & rs->ifree_mask;
94 #if defined(__x86_64__) && defined(__GNUC__)
101 __asm__("bsfq %1,%0\n\t"
102 : "=r" (i) : "rm" (mask));
104 rs->ifree_mask &= ~ ((regmask_t)1 << i);
110 for (i = 0; i < MONO_MAX_IREGS; ++i) {
111 if (mask & ((regmask_t)1 << i)) {
112 rs->ifree_mask &= ~ ((regmask_t)1 << i);
121 mono_regstate_free_int (MonoRegState *rs, int reg)
124 rs->ifree_mask |= (regmask_t)1 << reg;
125 rs->isymbolic [reg] = 0;
130 mono_regstate_alloc_float (MonoRegState *rs, regmask_t allow)
133 regmask_t mask = allow & rs->ffree_mask;
134 for (i = 0; i < MONO_MAX_FREGS; ++i) {
135 if (mask & ((regmask_t)1 << i)) {
136 rs->ffree_mask &= ~ ((regmask_t)1 << i);
144 mono_regstate_free_float (MonoRegState *rs, int reg)
147 rs->ffree_mask |= (regmask_t)1 << reg;
148 rs->fsymbolic [reg] = 0;
153 mono_regstate2_next_long (MonoRegState *rs)
155 int rval = rs->next_vreg;
163 mono_regname_full (int reg, gboolean fp)
166 return mono_arch_fregname (reg);
168 return mono_arch_regname (reg);
172 mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, gboolean fp)
176 regpair = (((guint32)hreg) << 24) + vreg;
178 g_assert (vreg >= MONO_MAX_FREGS);
179 g_assert (hreg < MONO_MAX_FREGS);
180 call->used_fregs |= 1 << hreg;
181 call->out_freg_args = g_slist_append_mempool (cfg->mempool, call->out_freg_args, (gpointer)(gssize)(regpair));
183 g_assert (vreg >= MONO_MAX_IREGS);
184 g_assert (hreg < MONO_MAX_IREGS);
185 call->used_iregs |= 1 << hreg;
186 call->out_ireg_args = g_slist_append_mempool (cfg->mempool, call->out_ireg_args, (gpointer)(gssize)(regpair));
191 resize_spill_info (MonoCompile *cfg, gboolean fp)
193 MonoSpillInfo *orig_info = fp ? cfg->spill_info_float : cfg->spill_info;
194 int orig_len = fp ? cfg->spill_info_float_len : cfg->spill_info_len;
195 int new_len = orig_len ? orig_len * 2 : 16;
196 MonoSpillInfo *new_info;
199 new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
201 memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
202 for (i = orig_len; i < new_len; ++i)
203 new_info [i].offset = -1;
206 cfg->spill_info = new_info;
207 cfg->spill_info_len = new_len;
209 cfg->spill_info_float = new_info;
210 cfg->spill_info_float_len = new_len;
215 * returns the offset used by spillvar. It allocates a new
216 * spill variable if necessary.
219 mono_spillvar_offset_int (MonoCompile *cfg, int spillvar)
223 #if defined (__mips__)
224 g_assert_not_reached();
226 if (G_UNLIKELY (spillvar >= cfg->spill_info_len)) {
227 resize_spill_info (cfg, FALSE);
228 g_assert (spillvar < cfg->spill_info_len);
231 info = &cfg->spill_info [spillvar];
232 if (info->offset == -1) {
233 cfg->stack_offset += sizeof (gpointer) - 1;
234 cfg->stack_offset &= ~(sizeof (gpointer) - 1);
236 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
237 info->offset = cfg->stack_offset;
238 cfg->stack_offset += sizeof (gpointer);
240 cfg->stack_offset += sizeof (gpointer);
241 info->offset = - cfg->stack_offset;
249 * returns the offset used by spillvar. It allocates a new
250 * spill float variable if necessary.
251 * (same as mono_spillvar_offset but for float)
254 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
258 #if defined (__mips__)
259 g_assert_not_reached();
261 if (G_UNLIKELY (spillvar >= cfg->spill_info_float_len)) {
262 resize_spill_info (cfg, TRUE);
263 g_assert (spillvar < cfg->spill_info_float_len);
266 info = &cfg->spill_info_float [spillvar];
267 if (info->offset == -1) {
268 cfg->stack_offset += sizeof (double) - 1;
269 cfg->stack_offset &= ~(sizeof (double) - 1);
271 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
272 info->offset = cfg->stack_offset;
273 cfg->stack_offset += sizeof (double);
275 cfg->stack_offset += sizeof (double);
276 info->offset = - cfg->stack_offset;
284 mono_spillvar_offset (MonoCompile *cfg, int spillvar, gboolean fp)
287 return mono_spillvar_offset_float (cfg, spillvar);
289 return mono_spillvar_offset_int (cfg, spillvar);
292 #if MONO_ARCH_USE_FPSTACK
295 * Creates a store for spilled floating point items
298 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
301 MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
303 store->inst_destbasereg = cfg->frame_reg;
304 store->inst_offset = mono_spillvar_offset_float (cfg, spill);
306 DEBUG (printf ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
311 * Creates a load for spilled floating point items
314 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
317 MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
319 load->inst_basereg = cfg->frame_reg;
320 load->inst_offset = mono_spillvar_offset_float (cfg, spill);
322 DEBUG (printf ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
326 #endif /* MONO_ARCH_USE_FPSTACK */
328 #define regmask(reg) (((regmask_t)1) << (reg))
330 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
331 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
332 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
333 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
334 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
335 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
336 #define ireg_is_freeable(r) is_local_ireg ((r))
337 #define freg_is_freeable(r) is_hard_freg ((r))
339 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
340 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
341 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
342 #define rassign(cfg,reg,fp) ((cfg)->rs->vassign [(reg)])
344 #ifdef MONO_ARCH_INST_IS_FLOAT
345 #define dreg_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
346 #define sreg1_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC1]))
347 #define sreg2_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC2]))
349 #define sreg1_is_fp(spec) (spec [MONO_INST_SRC1] == 'f')
350 #define sreg2_is_fp(spec) (spec [MONO_INST_SRC2] == 'f')
351 #define dreg_is_fp(spec) (spec [MONO_INST_DEST] == 'f')
354 #define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_get_spec ((ins)->opcode)))
355 #define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_get_spec ((ins)->opcode)))
356 #define dreg_is_fp_ins(ins) (dreg_is_fp (ins_get_spec ((ins)->opcode)))
358 #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)
360 #ifdef MONO_ARCH_IS_GLOBAL_IREG
361 #undef is_global_ireg
362 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
371 #if MONO_ARCH_USE_FPSTACK
372 int flags; /* used to track fp spill/load */
374 regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
377 #ifndef DISABLE_LOGGING
379 mono_print_ins (int i, MonoInst *ins)
381 const char *spec = ins_get_spec (ins->opcode);
382 printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
384 g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
386 if (spec [MONO_INST_DEST]) {
387 gboolean fp = dreg_is_fp_ins (ins);
388 if (is_soft_reg (ins->dreg, fp)) {
389 if (spec [MONO_INST_DEST] == 'b') {
390 if (ins->inst_offset == 0)
391 printf (" [R%d] <-", ins->dreg);
393 printf (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
396 printf (" R%d <-", ins->dreg);
397 } else if (spec [MONO_INST_DEST] == 'b') {
398 if (ins->inst_offset == 0)
399 printf (" [%s] <-", mono_arch_regname (ins->dreg));
401 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
403 printf (" %s <-", mono_regname_full (ins->dreg, fp));
405 if (spec [MONO_INST_SRC1]) {
406 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
407 if (is_soft_reg (ins->sreg1, fp))
408 printf (" R%d", ins->sreg1);
409 else if (spec [MONO_INST_SRC1] == 'b')
410 printf (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
412 printf (" %s", mono_regname_full (ins->sreg1, fp));
414 if (spec [MONO_INST_SRC2]) {
415 gboolean fp = (spec [MONO_INST_SRC2] == 'f');
416 if (is_soft_reg (ins->sreg2, fp))
417 printf (" R%d", ins->sreg2);
419 printf (" %s", mono_regname_full (ins->sreg2, fp));
421 if (spec [MONO_INST_CLOB])
422 printf (" clobbers: %c", spec [MONO_INST_CLOB]);
427 print_regtrack (RegTrack *t, int num)
433 for (i = 0; i < num; ++i) {
436 if (i >= MONO_MAX_IREGS) {
437 g_snprintf (buf, sizeof(buf), "R%d", i);
440 r = mono_arch_regname (i);
441 printf ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].killed_in);
444 #endif /* DISABLE_LOGGING */
446 typedef struct InstList InstList;
454 static inline InstList*
455 inst_list_prepend (guint8 *mem, InstList *list, MonoInst *data)
457 InstList *item = (InstList*)(gpointer)mem;
467 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
472 * If this function is called multiple times, the new instructions are inserted
473 * in the proper order.
477 prev = item->next->data;
479 while (prev->next != ins)
481 to_insert->next = ins;
482 prev->next = to_insert;
484 to_insert->next = ins;
488 * insert_after_ins insert the new instruction before item->data, so
489 * we have to modify it to point to the first of the prepended instructions.
491 if (item->data == ins)
492 item->data = to_insert;
496 insert_after_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
499 while (ins->next != item->prev->data)
502 to_insert->next = ins->next;
503 ins->next = to_insert;
507 * Force the spilling of the variable in the symbolic register 'reg'.
510 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg, gboolean fp)
514 int *assign, *symbolic;
516 assign = cfg->rs->vassign;
518 symbolic = cfg->rs->fsymbolic;
520 symbolic = cfg->rs->isymbolic;
522 sel = cfg->rs->vassign [reg];
523 /*i = cfg->rs->isymbolic [sel];
524 g_assert (i == reg);*/
526 spill = ++cfg->spill_count;
527 assign [i] = -spill - 1;
529 mono_regstate_free_float (cfg->rs, sel);
531 mono_regstate_free_int (cfg->rs, sel);
532 /* we need to create a spill var and insert a load to sel after the current instruction */
534 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
536 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
538 load->inst_basereg = cfg->frame_reg;
539 load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
540 insert_after_ins (ins, item, load);
541 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)));
543 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
545 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
551 /* This isn't defined on older glib versions and on some platforms */
552 #ifndef G_GUINT64_FORMAT
553 #define G_GUINT64_FORMAT "ul"
557 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_t regmask, int reg, gboolean fp)
561 int *assign, *symbolic;
563 assign = cfg->rs->vassign;
565 symbolic = cfg->rs->fsymbolic;
567 symbolic = cfg->rs->isymbolic;
569 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));
570 /* exclude the registers in the current instruction */
571 if ((sreg1_is_fp_ins (ins) == fp) && (reg != ins->sreg1) && (reg_is_freeable (ins->sreg1, fp) || (is_soft_reg (ins->sreg1, fp) && rassign (cfg, ins->sreg1, fp) >= 0))) {
572 if (is_soft_reg (ins->sreg1, fp))
573 regmask &= ~ (regmask (rassign (cfg, ins->sreg1, fp)));
575 regmask &= ~ (regmask (ins->sreg1));
576 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
578 if ((sreg2_is_fp_ins (ins) == fp) && (reg != ins->sreg2) && (reg_is_freeable (ins->sreg2, fp) || (is_soft_reg (ins->sreg2, fp) && rassign (cfg, ins->sreg2, fp) >= 0))) {
579 if (is_soft_reg (ins->sreg2, fp))
580 regmask &= ~ (regmask (rassign (cfg, ins->sreg2, fp)));
582 regmask &= ~ (regmask (ins->sreg2));
583 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
585 if ((dreg_is_fp_ins (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
586 regmask &= ~ (regmask (ins->dreg));
587 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
590 DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
591 g_assert (regmask); /* need at least a register we can free */
593 /* we should track prev_use and spill the register that's farther */
595 for (i = 0; i < MONO_MAX_FREGS; ++i) {
596 if (regmask & (regmask (i))) {
598 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
603 i = cfg->rs->fsymbolic [sel];
604 spill = ++cfg->spill_count;
605 cfg->rs->vassign [i] = -spill - 1;
606 mono_regstate_free_float (cfg->rs, sel);
609 for (i = 0; i < MONO_MAX_IREGS; ++i) {
610 if (regmask & (regmask (i))) {
612 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
617 i = cfg->rs->isymbolic [sel];
618 spill = ++cfg->spill_count;
619 cfg->rs->vassign [i] = -spill - 1;
620 mono_regstate_free_int (cfg->rs, sel);
623 /* we need to create a spill var and insert a load to sel after the current instruction */
624 MONO_INST_NEW (cfg, load, fp ? OP_LOADR8_MEMBASE : OP_LOAD_MEMBASE);
626 load->inst_basereg = cfg->frame_reg;
627 load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
628 insert_after_ins (ins, item, load);
629 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)));
631 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
633 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
640 free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
642 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
643 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
644 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
645 mono_regstate_free_int (cfg->rs, hreg);
650 free_up_reg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg, gboolean fp)
653 if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
654 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
655 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
656 mono_regstate_free_float (cfg->rs, hreg);
660 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
661 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
662 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
663 mono_regstate_free_int (cfg->rs, hreg);
669 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins, const unsigned char *ip, gboolean fp)
674 MONO_INST_NEW (cfg, copy, OP_FMOVE);
676 MONO_INST_NEW (cfg, copy, OP_MOVE);
682 copy->next = ins->next;
683 copy->cil_code = ins->cil_code;
686 DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
691 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins, gboolean fp)
694 MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
696 store->inst_destbasereg = cfg->frame_reg;
697 store->inst_offset = mono_spillvar_offset (cfg, spill, fp);
699 store->next = ins->next;
702 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)));
706 /* flags used in reginfo->flags */
708 MONO_FP_NEEDS_LOAD_SPILL = regmask (0),
709 MONO_FP_NEEDS_SPILL = regmask (1),
710 MONO_FP_NEEDS_LOAD = regmask (2)
714 alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
718 if (info && info->preferred_mask) {
719 val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
721 DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
726 val = mono_regstate_alloc_int (cfg->rs, dest_mask);
728 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
734 alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg)
738 val = mono_regstate_alloc_float (cfg->rs, dest_mask);
741 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
748 alloc_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
751 return alloc_float_reg (cfg, tmp, ins, dest_mask, sym_reg);
753 return alloc_int_reg (cfg, tmp, ins, dest_mask, sym_reg, info);
757 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
760 g_assert (reg >= MONO_MAX_FREGS);
761 g_assert (hreg < MONO_MAX_FREGS);
762 g_assert (! is_global_freg (hreg));
764 rs->vassign [reg] = hreg;
765 rs->fsymbolic [hreg] = reg;
766 rs->ffree_mask &= ~ (regmask (hreg));
769 g_assert (reg >= MONO_MAX_IREGS);
770 g_assert (hreg < MONO_MAX_IREGS);
772 /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */
773 g_assert (! is_global_ireg (hreg));
776 rs->vassign [reg] = hreg;
777 rs->isymbolic [hreg] = reg;
778 rs->ifree_mask &= ~ (regmask (hreg));
783 assign_ireg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg)
785 assign_reg (cfg, rs, reg, hreg, FALSE);
789 * Local register allocation.
790 * We first scan the list of instructions and we save the liveness info of
791 * each register (when the register is first used, when it's value is set etc.).
792 * We also reverse the list of instructions (in the InstList list) because assigning
793 * registers backwards allows for more tricks to be used.
796 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
799 MonoRegState *rs = cfg->rs;
800 int i, val, fpcount, ins_count;
802 InstList *tmp, *reversed = NULL;
804 GList *fspill_list = NULL;
807 guint8 *inst_list, *mem;
808 #if MONO_ARCH_USE_FPSTACK
809 gboolean need_fpstack = use_fpstack;
815 rs->next_vreg = bb->max_vreg;
816 mono_regstate_assign (rs);
818 rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
819 rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
822 rs->ffree_mask = 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE));
826 /*if (cfg->opt & MONO_OPT_COPYPROP)
827 local_copy_prop (cfg, ins);*/
829 if (cfg->reginfo && cfg->reginfo_len < rs->next_vreg) {
832 reginfo = cfg->reginfo;
834 cfg->reginfo_len = MAX (256, rs->next_vreg * 2);
835 reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
838 g_assert (cfg->reginfo_len >= rs->next_vreg);
840 memset (reginfo, 0, rs->next_vreg * sizeof (RegTrack));
843 for (ins = bb->code; ins; ins = ins->next) {
847 if (cfg->reverse_inst_list && (cfg->reverse_inst_list_len < ins_count)) {
848 cfg->reverse_inst_list = NULL;
851 inst_list = cfg->reverse_inst_list;
853 cfg->reverse_inst_list_len = MAX (ins_count, 1024);
854 inst_list = cfg->reverse_inst_list = mono_mempool_alloc (cfg->mempool, cfg->reverse_inst_list_len * sizeof (InstList));
860 DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb->block_num));
861 /* forward pass on the instructions to collect register liveness info */
862 for (ins = bb->code; ins; ins = ins->next) {
863 spec = ins_get_spec (ins->opcode);
865 if (G_UNLIKELY (spec == MONO_ARCH_CPU_SPEC)) {
866 g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
869 DEBUG (mono_print_ins (i, ins));
874 #if MONO_ARCH_USE_FPSTACK
878 if (spec [MONO_INST_SRC1] == 'f') {
879 spill = g_list_first (fspill_list);
880 if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
881 reginfo [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
882 fspill_list = g_list_remove (fspill_list, spill->data);
887 if (spec [MONO_INST_SRC2] == 'f') {
888 spill = g_list_first (fspill_list);
890 reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
891 fspill_list = g_list_remove (fspill_list, spill->data);
892 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
894 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
895 reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
901 if (dreg_is_fp (spec)) {
902 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
903 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
904 reginfo [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
906 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
915 if (spec [MONO_INST_SRC1]) {
916 //reginfo [ins->sreg1].prev_use = reginfo [ins->sreg1].last_use;
917 //reginfo [ins->sreg1].last_use = i;
918 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
919 /* The virtual register is allocated sequentially */
920 //reginfo [ins->sreg1 + 1].prev_use = reginfo [ins->sreg1 + 1].last_use;
921 //reginfo [ins->sreg1 + 1].last_use = i;
922 if (reginfo [ins->sreg1 + 1].born_in == 0 || reginfo [ins->sreg1 + 1].born_in > i)
923 reginfo [ins->sreg1 + 1].born_in = i;
928 if (spec [MONO_INST_SRC2]) {
929 //reginfo [ins->sreg2].prev_use = reginfo [ins->sreg2].last_use;
930 //reginfo [ins->sreg2].last_use = i;
931 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
932 /* The virtual register is allocated sequentially */
933 //reginfo [ins->sreg2 + 1].prev_use = reginfo [ins->sreg2 + 1].last_use;
934 //reginfo [ins->sreg2 + 1].last_use = i;
935 if (reginfo [ins->sreg2 + 1].born_in == 0 || reginfo [ins->sreg2 + 1].born_in > i)
936 reginfo [ins->sreg2 + 1].born_in = i;
941 if (spec [MONO_INST_DEST]) {
944 if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
945 reginfo [ins->dreg].killed_in = i;
946 //reginfo [ins->dreg].prev_use = reginfo [ins->dreg].last_use;
947 //reginfo [ins->dreg].last_use = i;
948 if (reginfo [ins->dreg].born_in == 0 || reginfo [ins->dreg].born_in > i)
949 reginfo [ins->dreg].born_in = i;
951 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
953 reginfo [ins->dreg].preferred_mask = (regmask (dest_dreg));
955 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
956 /* The virtual register is allocated sequentially */
957 //reginfo [ins->dreg + 1].prev_use = reginfo [ins->dreg + 1].last_use;
958 //reginfo [ins->dreg + 1].last_use = i;
959 if (reginfo [ins->dreg + 1].born_in == 0 || reginfo [ins->dreg + 1].born_in > i)
960 reginfo [ins->dreg + 1].born_in = i;
961 if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
962 reginfo [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
968 if (spec [MONO_INST_CLOB] == 'c') {
969 /* A call instruction implicitly uses all registers in call->out_ireg_args */
971 MonoCallInst *call = (MonoCallInst*)ins;
974 list = call->out_ireg_args;
980 regpair = (guint32)(gssize)(list->data);
981 hreg = regpair >> 24;
982 reg = regpair & 0xffffff;
984 //reginfo [reg].prev_use = reginfo [reg].last_use;
985 //reginfo [reg].last_use = i;
987 list = g_slist_next (list);
991 list = call->out_freg_args;
992 if (!use_fpstack && list) {
997 regpair = (guint32)(gssize)(list->data);
998 hreg = regpair >> 24;
999 reg = regpair & 0xffffff;
1001 //reginfo [reg].prev_use = reginfo [reg].last_use;
1002 //reginfo [reg].last_use = i;
1004 list = g_slist_next (list);
1009 reversed = inst_list_prepend (mem, reversed, ins);
1010 mem += sizeof (InstList);
1014 // todo: check if we have anything left on fp stack, in verify mode?
1017 DEBUG (print_regtrack (reginfo, rs->next_vreg));
1020 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
1021 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
1022 int dreg_high, sreg1_high;
1023 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
1024 regmask_t dreg_fixed_mask, sreg1_fixed_mask, sreg2_fixed_mask;
1025 const unsigned char *ip;
1028 spec = ins_get_spec (ins->opcode);
1039 dreg_mask = dreg_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1040 sreg1_mask = sreg1_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1041 sreg2_mask = sreg2_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1043 DEBUG (printf ("processing:"));
1044 DEBUG (mono_print_ins (i, ins));
1051 dest_sreg1 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC1]);
1052 dest_sreg2 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC2]);
1053 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
1054 clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
1055 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
1057 #ifdef MONO_ARCH_INST_FIXED_MASK
1058 sreg1_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC1]);
1059 sreg2_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC2]);
1060 dreg_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_DEST]);
1062 sreg1_fixed_mask = sreg2_fixed_mask = dreg_fixed_mask = 0;
1068 #if MONO_ARCH_USE_FPSTACK
1069 if (need_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
1070 if (dreg_is_fp (spec)) {
1071 if (reginfo [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
1074 spill_node = g_list_first (fspill_list);
1075 g_assert (spill_node);
1077 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
1078 insert_before_ins (ins, tmp, store);
1079 fspill_list = g_list_remove (fspill_list, spill_node->data);
1084 if (spec [MONO_INST_SRC1] == 'f') {
1085 if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
1087 MonoInst *store = NULL;
1089 if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1091 spill_node = g_list_first (fspill_list);
1092 g_assert (spill_node);
1094 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);
1095 fspill_list = g_list_remove (fspill_list, spill_node->data);
1099 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1100 load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
1101 insert_before_ins (ins, tmp, load);
1103 insert_before_ins (load, tmp, store);
1107 if (spec [MONO_INST_SRC2] == 'f') {
1108 if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
1110 MonoInst *store = NULL;
1112 if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1115 spill_node = g_list_first (fspill_list);
1116 g_assert (spill_node);
1117 if (spec [MONO_INST_SRC1] == 'f' && (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
1118 spill_node = g_list_next (spill_node);
1120 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
1121 fspill_list = g_list_remove (fspill_list, spill_node->data);
1125 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1126 load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
1127 insert_before_ins (ins, tmp, load);
1129 insert_before_ins (load, tmp, store);
1138 if (dest_sreg2 != -1) {
1139 if (rs->ifree_mask & (regmask (dest_sreg2))) {
1140 if (is_global_ireg (ins->sreg2)) {
1141 /* Argument already in hard reg, need to copy */
1142 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1143 insert_before_ins (ins, tmp, copy);
1146 val = rs->vassign [ins->sreg2];
1148 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
1149 assign_reg (cfg, rs, ins->sreg2, dest_sreg2, FALSE);
1150 } else if (val < -1) {
1152 g_assert_not_reached ();
1154 /* Argument already in hard reg, need to copy */
1155 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, val, NULL, ip, FALSE);
1156 insert_before_ins (ins, tmp, copy);
1160 int need_spill = TRUE;
1162 dreg_mask &= ~ (regmask (dest_sreg2));
1163 sreg1_mask &= ~ (regmask (dest_sreg2));
1166 * First check if dreg is assigned to dest_sreg2, since we
1167 * can't spill a dreg.
1169 val = rs->vassign [ins->dreg];
1170 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
1172 * the destination register is already assigned to
1173 * dest_sreg2: we need to allocate another register for it
1174 * and then copy from this to dest_sreg2.
1177 new_dest = alloc_int_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg]);
1178 g_assert (new_dest >= 0);
1179 DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
1181 prev_dreg = ins->dreg;
1182 assign_ireg (cfg, rs, ins->dreg, new_dest);
1183 clob_dreg = ins->dreg;
1184 create_copy_ins (cfg, dest_sreg2, new_dest, ins, ip, FALSE);
1185 mono_regstate_free_int (rs, dest_sreg2);
1189 if (is_global_ireg (ins->sreg2)) {
1190 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1191 insert_before_ins (ins, tmp, copy);
1194 val = rs->vassign [ins->sreg2];
1195 if (val == dest_sreg2) {
1196 /* sreg2 is already assigned to the correct register */
1199 else if ((val >= 0) || (val < -1)) {
1200 /* FIXME: sreg2 already assigned to another register */
1201 g_assert_not_reached ();
1206 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1207 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
1208 mono_regstate_free_int (rs, dest_sreg2);
1211 if (!is_global_ireg (ins->sreg2))
1212 /* force-set sreg2 */
1213 assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1215 ins->sreg2 = dest_sreg2;
1221 fp = dreg_is_fp (spec);
1222 if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
1223 prev_dreg = ins->dreg;
1225 if (spec [MONO_INST_DEST] == 'b') {
1227 * The dest reg is read by the instruction, not written, so
1228 * avoid allocating sreg1/sreg2 to the same reg.
1230 if (dest_sreg1 != -1)
1231 dreg_mask &= ~ (regmask (dest_sreg1));
1232 if (dest_sreg2 != -1)
1233 dreg_mask &= ~ (regmask (dest_sreg2));
1235 val = rassign (cfg, ins->dreg, fp);
1236 if (is_soft_reg (ins->dreg, fp) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
1237 /* DREG is already allocated to a register needed for sreg1 */
1238 get_register_force_spilling (cfg, tmp, ins, ins->dreg, FALSE);
1239 mono_regstate_free_int (rs, val);
1244 * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1245 * various complex situations.
1247 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1248 guint32 dreg2, dest_dreg2;
1250 g_assert (is_soft_reg (ins->dreg, fp));
1252 if (dest_dreg != -1) {
1253 if (rs->vassign [ins->dreg] != dest_dreg)
1254 free_up_ireg (cfg, tmp, ins, dest_dreg);
1256 dreg2 = ins->dreg + 1;
1257 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
1258 if (dest_dreg2 != -1) {
1259 if (rs->vassign [dreg2] != dest_dreg2)
1260 free_up_ireg (cfg, tmp, ins, dest_dreg2);
1265 if (dreg_fixed_mask) {
1267 if (is_global_ireg (ins->dreg)) {
1269 * The argument is already in a hard reg, but that reg is
1270 * not usable by this instruction, so allocate a new one.
1272 val = mono_regstate_alloc_int (rs, dreg_fixed_mask);
1274 val = get_register_spilling (cfg, tmp, ins, dreg_fixed_mask, -1, fp);
1275 mono_regstate_free_int (rs, val);
1281 dreg_mask &= dreg_fixed_mask;
1284 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
1285 if (dest_dreg != -1)
1286 dreg_mask = (regmask (dest_dreg));
1288 val = rassign (cfg, ins->dreg, fp);
1293 /* the register gets spilled after this inst */
1296 val = alloc_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg], fp);
1297 assign_reg (cfg, rs, ins->dreg, val, fp);
1299 create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
1302 DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
1306 /* Handle regpairs */
1307 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1308 int reg2 = prev_dreg + 1;
1311 g_assert (prev_dreg > -1);
1312 g_assert (!is_global_ireg (rs->vassign [prev_dreg]));
1313 mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->vassign [prev_dreg]);
1316 mask &= ~regmask (X86_ECX);
1318 val = rs->vassign [reg2];
1322 /* the register gets spilled after this inst */
1325 val = mono_regstate_alloc_int (rs, mask);
1327 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1329 create_spilled_store (cfg, spill, val, reg2, ins, fp);
1332 if (! (mask & (regmask (val)))) {
1333 val = mono_regstate_alloc_int (rs, mask);
1335 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1337 /* Reallocate hreg to the correct register */
1338 create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
1340 mono_regstate_free_int (rs, rs->vassign [reg2]);
1344 DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1345 assign_reg (cfg, rs, reg2, val, fp);
1348 ins->backend.reg3 = val;
1350 if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1351 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1352 mono_regstate_free_int (rs, val);
1356 if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && reginfo [prev_dreg].born_in >= i) {
1358 * In theory, we could free up the hreg even if the vreg is alive,
1359 * but branches inside bblocks force us to assign the same hreg
1360 * to a vreg every time it is encountered.
1362 int dreg = rassign (cfg, prev_dreg, fp);
1363 g_assert (dreg >= 0);
1364 DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, reginfo [prev_dreg].born_in));
1366 mono_regstate_free_float (rs, dreg);
1368 mono_regstate_free_int (rs, dreg);
1371 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1372 /* this instruction only outputs to dest_dreg, need to copy */
1373 create_copy_ins (cfg, ins->dreg, dest_dreg, ins, ip, fp);
1374 ins->dreg = dest_dreg;
1377 if (rs->fsymbolic [dest_dreg] >= MONO_MAX_FREGS)
1378 free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1381 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1382 free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1386 if (spec [MONO_INST_DEST] == 'b') {
1388 * The dest reg is read by the instruction, not written, so
1389 * avoid allocating sreg1/sreg2 to the same reg.
1391 sreg1_mask &= ~ (regmask (ins->dreg));
1392 sreg2_mask &= ~ (regmask (ins->dreg));
1398 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1399 DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1400 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
1401 mono_regstate_free_int (rs, clob_reg);
1404 if (spec [MONO_INST_CLOB] == 'c') {
1405 int j, s, dreg, dreg2;
1408 clob_mask = MONO_ARCH_CALLEE_REGS;
1411 * Need to avoid spilling the dreg since the dreg is not really
1412 * clobbered by the call.
1414 if ((prev_dreg != -1) && !dreg_is_fp (spec))
1415 dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
1419 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
1420 dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (spec));
1424 for (j = 0; j < MONO_MAX_IREGS; ++j) {
1426 if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
1427 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
1428 mono_regstate_free_int (rs, j);
1433 clob_mask = MONO_ARCH_CALLEE_FREGS;
1434 if ((prev_dreg != -1) && dreg_is_fp (spec))
1435 dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
1439 for (j = 0; j < MONO_MAX_FREGS; ++j) {
1441 if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
1442 get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
1443 mono_regstate_free_float (rs, j);
1450 * TRACK ARGUMENT REGS
1452 if (spec [MONO_INST_CLOB] == 'c') {
1453 MonoCallInst *call = (MonoCallInst*)ins;
1457 * This needs to be done before assigning sreg1, so sreg1 will
1458 * not be assigned one of the argument regs.
1462 * Assign all registers in call->out_reg_args to the proper
1463 * argument registers.
1466 list = call->out_ireg_args;
1472 regpair = (guint32)(gssize)(list->data);
1473 hreg = regpair >> 24;
1474 reg = regpair & 0xffffff;
1476 assign_reg (cfg, rs, reg, hreg, FALSE);
1478 sreg1_mask &= ~(regmask (hreg));
1480 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1482 list = g_slist_next (list);
1486 list = call->out_freg_args;
1487 if (list && !use_fpstack) {
1492 regpair = (guint32)(gssize)(list->data);
1493 hreg = regpair >> 24;
1494 reg = regpair & 0xffffff;
1496 assign_reg (cfg, rs, reg, hreg, TRUE);
1498 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
1500 list = g_slist_next (list);
1508 fp = sreg1_is_fp (spec);
1509 if ((!fp || (fp && !use_fpstack))) {
1510 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
1511 g_assert (is_soft_reg (ins->sreg1, fp));
1513 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1514 if (dest_sreg1 != -1)
1515 g_assert (dest_sreg1 == ins->dreg);
1516 val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
1517 g_assert (val >= 0);
1518 assign_reg (cfg, rs, ins->sreg1, val, fp);
1520 DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1522 g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
1523 val = mono_regstate_alloc_int (rs, regmask (dreg_high));
1524 g_assert (val >= 0);
1525 assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
1527 DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
1529 /* Skip rest of this section */
1533 if (sreg1_fixed_mask) {
1535 if (is_global_ireg (ins->sreg1)) {
1537 * The argument is already in a hard reg, but that reg is
1538 * not usable by this instruction, so allocate a new one.
1540 val = mono_regstate_alloc_int (rs, sreg1_fixed_mask);
1542 val = get_register_spilling (cfg, tmp, ins, sreg1_fixed_mask, -1, fp);
1543 mono_regstate_free_int (rs, val);
1546 /* Fall through to the dest_sreg1 != -1 case */
1549 sreg1_mask &= sreg1_fixed_mask;
1552 if (dest_sreg1 != -1) {
1553 sreg1_mask = regmask (dest_sreg1);
1555 if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
1556 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1557 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
1558 mono_regstate_free_int (rs, dest_sreg1);
1560 if (is_global_ireg (ins->sreg1)) {
1561 /* The argument is already in a hard reg, need to copy */
1562 MonoInst *copy = create_copy_ins (cfg, dest_sreg1, ins->sreg1, NULL, ip, FALSE);
1563 insert_before_ins (ins, tmp, copy);
1564 ins->sreg1 = dest_sreg1;
1568 if (is_soft_reg (ins->sreg1, fp)) {
1569 val = rassign (cfg, ins->sreg1, fp);
1570 prev_sreg1 = ins->sreg1;
1574 /* the register gets spilled after this inst */
1578 if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
1580 * Allocate the same hreg to sreg1 as well so the
1581 * peephole can get rid of the move.
1583 sreg1_mask = regmask (ins->dreg);
1586 val = alloc_reg (cfg, tmp, ins, sreg1_mask, ins->sreg1, ®info [ins->sreg1], fp);
1587 assign_reg (cfg, rs, ins->sreg1, val, fp);
1588 DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1591 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
1593 * Need to insert before the instruction since it can
1596 insert_before_ins (ins, tmp, store);
1599 else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1600 create_copy_ins (cfg, dest_sreg1, val, ins, ip, fp);
1608 sreg2_mask &= ~(regmask (ins->sreg1));
1611 /* Handle the case when sreg1 is a regpair but dreg is not */
1612 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1]) && (spec [MONO_INST_CLOB] != '1')) {
1613 int reg2 = prev_sreg1 + 1;
1616 g_assert (prev_sreg1 > -1);
1617 g_assert (!is_global_ireg (rs->vassign [prev_sreg1]));
1618 mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->vassign [prev_sreg1]);
1619 val = rs->vassign [reg2];
1623 /* the register gets spilled after this inst */
1626 val = mono_regstate_alloc_int (rs, mask);
1628 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1630 g_assert_not_reached ();
1633 if (! (mask & (regmask (val)))) {
1634 /* The vreg is already allocated to a wrong hreg */
1636 g_assert_not_reached ();
1638 val = mono_regstate_alloc_int (rs, mask);
1640 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1642 /* Reallocate hreg to the correct register */
1643 create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
1645 mono_regstate_free_int (rs, rs->vassign [reg2]);
1651 DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1652 assign_reg (cfg, rs, reg2, val, fp);
1655 /* Handle dreg==sreg1 */
1656 if (((dreg_is_fp (spec) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1657 MonoInst *sreg2_copy = NULL;
1659 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
1661 if (ins->dreg == ins->sreg2) {
1663 * copying sreg1 to dreg could clobber sreg2, so allocate a new
1666 int reg2 = alloc_reg (cfg, tmp, ins, dreg_mask, ins->sreg2, NULL, fp);
1668 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
1669 sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
1670 prev_sreg2 = ins->sreg2 = reg2;
1673 mono_regstate_free_float (rs, reg2);
1675 mono_regstate_free_int (rs, reg2);
1678 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
1679 /* Copying sreg1_high to dreg could also clobber sreg2 */
1680 if (rs->vassign [prev_sreg1 + 1] == ins->sreg2)
1682 g_assert_not_reached ();
1685 * sreg1 and dest are already allocated to the same regpair by the
1686 * SREG1 allocation code.
1688 g_assert (ins->sreg1 == ins->dreg);
1689 g_assert (dreg_high == sreg1_high);
1692 DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
1693 copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
1694 insert_before_ins (ins, tmp, copy);
1697 insert_before_ins (copy, tmp, sreg2_copy);
1700 * Need to prevent sreg2 to be allocated to sreg1, since that
1701 * would screw up the previous copy.
1703 sreg2_mask &= ~ (regmask (ins->sreg1));
1704 /* we set sreg1 to dest as well */
1705 prev_sreg1 = ins->sreg1 = ins->dreg;
1706 sreg2_mask &= ~ (regmask (ins->dreg));
1712 fp = sreg2_is_fp (spec);
1713 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
1714 g_assert_not_reached ();
1715 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
1716 val = rassign (cfg, ins->sreg2, fp);
1721 /* the register gets spilled after this inst */
1724 val = alloc_reg (cfg, tmp, ins, sreg2_mask, ins->sreg2, ®info [ins->sreg2], fp);
1725 assign_reg (cfg, rs, ins->sreg2, val, fp);
1726 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
1728 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg2, NULL, fp);
1730 * Need to insert before the instruction since it can
1733 insert_before_ins (ins, tmp, store);
1742 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1743 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1744 mono_regstate_free_int (rs, ins->sreg1);
1746 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1747 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1748 mono_regstate_free_int (rs, ins->sreg2);
1751 DEBUG (mono_print_ins (i, ins));
1752 /* this may result from a insert_before call */
1754 bb->code = tmp->data;
1758 g_list_free (fspill_list);
1762 mono_opcode_to_cond (int opcode)
1773 case OP_COND_EXC_EQ:
1774 case OP_COND_EXC_IEQ:
1780 case OP_COND_EXC_NE_UN:
1781 case OP_COND_EXC_INE_UN:
1801 case OP_COND_EXC_LT:
1802 case OP_COND_EXC_ILT:
1812 case OP_COND_EXC_GT:
1813 case OP_COND_EXC_IGT:
1820 case OP_COND_EXC_LE_UN:
1821 case OP_COND_EXC_ILE_UN:
1836 case OP_COND_EXC_LT_UN:
1837 case OP_COND_EXC_ILT_UN:
1847 case OP_COND_EXC_GT_UN:
1848 case OP_COND_EXC_IGT_UN:
1851 printf ("%s\n", mono_inst_name (opcode));
1852 g_assert_not_reached ();
1857 mono_opcode_to_type (int opcode, int cmp_opcode)
1859 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1861 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1863 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLT_UN))
1865 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1867 else if ((opcode >= OP_LBEQ) && (opcode <= OP_LBLT_UN))
1869 else if ((opcode >= OP_LCEQ) && (opcode <= OP_LCLT_UN))
1871 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLT_UN))
1873 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1875 else if ((opcode >= OP_COND_EXC_IEQ) && (opcode <= OP_COND_EXC_ILT_UN))
1877 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1878 switch (cmp_opcode) {
1880 case OP_ICOMPARE_IMM:
1886 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1892 mono_is_regsize_var (MonoType *t)
1896 t = mono_type_get_underlying_type (t);
1898 case MONO_TYPE_BOOLEAN:
1899 case MONO_TYPE_CHAR:
1909 case MONO_TYPE_FNPTR:
1910 #if SIZEOF_VOID_P == 8
1915 case MONO_TYPE_OBJECT:
1916 case MONO_TYPE_STRING:
1917 case MONO_TYPE_CLASS:
1918 case MONO_TYPE_SZARRAY:
1919 case MONO_TYPE_ARRAY:
1921 case MONO_TYPE_GENERICINST:
1922 if (!mono_type_generic_inst_is_valuetype (t))
1925 case MONO_TYPE_VALUETYPE: