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 mono_regstate_assign (MonoRegState *rs)
52 if (rs->next_vreg > rs->vassign_size) {
54 rs->vassign_size = MAX (rs->next_vreg, 256);
55 rs->vassign = g_malloc (rs->vassign_size * sizeof (int));
58 memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
59 memset (rs->vassign, -1, sizeof (rs->vassign [0]) * rs->next_vreg);
61 memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
65 mono_regstate_alloc_int (MonoRegState *rs, regmask_t allow)
67 regmask_t mask = allow & rs->ifree_mask;
69 #if defined(__x86_64__) && defined(__GNUC__)
76 __asm__("bsfq %1,%0\n\t"
77 : "=r" (i) : "rm" (mask));
79 rs->ifree_mask &= ~ ((regmask_t)1 << i);
85 for (i = 0; i < MONO_MAX_IREGS; ++i) {
86 if (mask & ((regmask_t)1 << i)) {
87 rs->ifree_mask &= ~ ((regmask_t)1 << i);
96 mono_regstate_free_int (MonoRegState *rs, int reg)
99 rs->ifree_mask |= (regmask_t)1 << reg;
100 rs->isymbolic [reg] = 0;
105 mono_regstate_alloc_float (MonoRegState *rs, regmask_t allow)
108 regmask_t mask = allow & rs->ffree_mask;
109 for (i = 0; i < MONO_MAX_FREGS; ++i) {
110 if (mask & ((regmask_t)1 << i)) {
111 rs->ffree_mask &= ~ ((regmask_t)1 << i);
119 mono_regstate_free_float (MonoRegState *rs, int reg)
122 rs->ffree_mask |= (regmask_t)1 << reg;
123 rs->fsymbolic [reg] = 0;
128 mono_regname_full (int reg, gboolean fp)
131 return mono_arch_fregname (reg);
133 return mono_arch_regname (reg);
137 mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, gboolean fp)
141 regpair = (((guint32)hreg) << 24) + vreg;
143 g_assert (vreg >= MONO_MAX_FREGS);
144 g_assert (hreg < MONO_MAX_FREGS);
145 call->used_fregs |= 1 << hreg;
146 call->out_freg_args = g_slist_append_mempool (cfg->mempool, call->out_freg_args, (gpointer)(gssize)(regpair));
148 g_assert (vreg >= MONO_MAX_IREGS);
149 g_assert (hreg < MONO_MAX_IREGS);
150 call->used_iregs |= 1 << hreg;
151 call->out_ireg_args = g_slist_append_mempool (cfg->mempool, call->out_ireg_args, (gpointer)(gssize)(regpair));
156 resize_spill_info (MonoCompile *cfg, gboolean fp)
158 MonoSpillInfo *orig_info = fp ? cfg->spill_info_float : cfg->spill_info;
159 int orig_len = fp ? cfg->spill_info_float_len : cfg->spill_info_len;
160 int new_len = orig_len ? orig_len * 2 : 16;
161 MonoSpillInfo *new_info;
164 new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
166 memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
167 for (i = orig_len; i < new_len; ++i)
168 new_info [i].offset = -1;
171 cfg->spill_info = new_info;
172 cfg->spill_info_len = new_len;
174 cfg->spill_info_float = new_info;
175 cfg->spill_info_float_len = new_len;
180 * returns the offset used by spillvar. It allocates a new
181 * spill variable if necessary.
184 mono_spillvar_offset_int (MonoCompile *cfg, int spillvar)
188 #if defined (__mips__)
189 g_assert_not_reached();
191 if (G_UNLIKELY (spillvar >= cfg->spill_info_len)) {
192 resize_spill_info (cfg, FALSE);
193 g_assert (spillvar < cfg->spill_info_len);
196 info = &cfg->spill_info [spillvar];
197 if (info->offset == -1) {
198 cfg->stack_offset += sizeof (gpointer) - 1;
199 cfg->stack_offset &= ~(sizeof (gpointer) - 1);
201 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
202 info->offset = cfg->stack_offset;
203 cfg->stack_offset += sizeof (gpointer);
205 cfg->stack_offset += sizeof (gpointer);
206 info->offset = - cfg->stack_offset;
214 * returns the offset used by spillvar. It allocates a new
215 * spill float variable if necessary.
216 * (same as mono_spillvar_offset but for float)
219 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
223 #if defined (__mips__)
224 g_assert_not_reached();
226 if (G_UNLIKELY (spillvar >= cfg->spill_info_float_len)) {
227 resize_spill_info (cfg, TRUE);
228 g_assert (spillvar < cfg->spill_info_float_len);
231 info = &cfg->spill_info_float [spillvar];
232 if (info->offset == -1) {
233 cfg->stack_offset += sizeof (double) - 1;
234 cfg->stack_offset &= ~(sizeof (double) - 1);
236 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
237 info->offset = cfg->stack_offset;
238 cfg->stack_offset += sizeof (double);
240 cfg->stack_offset += sizeof (double);
241 info->offset = - cfg->stack_offset;
249 mono_spillvar_offset (MonoCompile *cfg, int spillvar, gboolean fp)
252 return mono_spillvar_offset_float (cfg, spillvar);
254 return mono_spillvar_offset_int (cfg, spillvar);
257 #if MONO_ARCH_USE_FPSTACK
260 * Creates a store for spilled floating point items
263 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
266 MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
268 store->inst_destbasereg = cfg->frame_reg;
269 store->inst_offset = mono_spillvar_offset_float (cfg, spill);
271 DEBUG (printf ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
276 * Creates a load for spilled floating point items
279 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
282 MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
284 load->inst_basereg = cfg->frame_reg;
285 load->inst_offset = mono_spillvar_offset_float (cfg, spill);
287 DEBUG (printf ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
291 #endif /* MONO_ARCH_USE_FPSTACK */
293 #define regmask(reg) (((regmask_t)1) << (reg))
295 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
296 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
297 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
298 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
299 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
300 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
301 #define ireg_is_freeable(r) is_local_ireg ((r))
302 #define freg_is_freeable(r) is_hard_freg ((r))
304 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
305 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
306 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
308 #ifdef MONO_ARCH_INST_IS_FLOAT
309 #define dreg_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
310 #define sreg1_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC1]))
311 #define sreg2_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC2]))
313 #define sreg1_is_fp(spec) (spec [MONO_INST_SRC1] == 'f')
314 #define sreg2_is_fp(spec) (spec [MONO_INST_SRC2] == 'f')
315 #define dreg_is_fp(spec) (spec [MONO_INST_DEST] == 'f')
318 #define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_get_spec ((ins)->opcode)))
319 #define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_get_spec ((ins)->opcode)))
320 #define dreg_is_fp_ins(ins) (dreg_is_fp (ins_get_spec ((ins)->opcode)))
322 #define regpair_reg2_mask(desc,hreg1) ((MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1) != -1) ? (regmask (MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1))) : MONO_ARCH_CALLEE_REGS)
324 #ifdef MONO_ARCH_IS_GLOBAL_IREG
325 #undef is_global_ireg
326 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
335 #if MONO_ARCH_USE_FPSTACK
336 int flags; /* used to track fp spill/load */
338 regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
341 #ifndef DISABLE_LOGGING
343 mono_print_ins_index (int i, MonoInst *ins)
345 const char *spec = ins_get_spec (ins->opcode);
347 printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
349 printf (" %s", mono_inst_name (ins->opcode));
351 g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
353 if (spec [MONO_INST_DEST]) {
354 gboolean fp = dreg_is_fp_ins (ins);
355 if (is_soft_reg (ins->dreg, fp)) {
356 if (spec [MONO_INST_DEST] == 'b') {
357 if (ins->inst_offset == 0)
358 printf (" [R%d] <-", ins->dreg);
360 printf (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
363 printf (" R%d <-", ins->dreg);
364 } else if (spec [MONO_INST_DEST] == 'b') {
365 if (ins->inst_offset == 0)
366 printf (" [%s] <-", mono_arch_regname (ins->dreg));
368 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
370 printf (" %s <-", mono_regname_full (ins->dreg, fp));
372 if (spec [MONO_INST_SRC1]) {
373 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
374 if (is_soft_reg (ins->sreg1, fp))
375 printf (" R%d", ins->sreg1);
376 else if (spec [MONO_INST_SRC1] == 'b')
377 printf (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
379 printf (" %s", mono_regname_full (ins->sreg1, fp));
381 if (spec [MONO_INST_SRC2]) {
382 gboolean fp = (spec [MONO_INST_SRC2] == 'f');
383 if (is_soft_reg (ins->sreg2, fp))
384 printf (" R%d", ins->sreg2);
386 printf (" %s", mono_regname_full (ins->sreg2, fp));
388 if (spec [MONO_INST_CLOB])
389 printf (" clobbers: %c", spec [MONO_INST_CLOB]);
394 print_regtrack (RegTrack *t, int num)
400 for (i = 0; i < num; ++i) {
403 if (i >= MONO_MAX_IREGS) {
404 g_snprintf (buf, sizeof(buf), "R%d", i);
407 r = mono_arch_regname (i);
408 printf ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].killed_in);
413 mono_print_ins_index (int i, MonoInst *ins)
416 #endif /* DISABLE_LOGGING */
419 mono_print_ins (MonoInst *ins)
421 mono_print_ins_index (-1, ins);
425 insert_before_ins (MonoInst *ins, MonoInst* to_insert)
427 MONO_INST_LIST_ADD_TAIL (&to_insert->node, &ins->node);
431 * Force the spilling of the variable in the symbolic register 'reg'.
434 get_register_force_spilling (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, int reg, gboolean fp)
438 int *assign, *symbolic;
440 assign = cfg->rs->vassign;
442 symbolic = cfg->rs->fsymbolic;
444 symbolic = cfg->rs->isymbolic;
446 sel = cfg->rs->vassign [reg];
447 /*i = cfg->rs->isymbolic [sel];
448 g_assert (i == reg);*/
450 spill = ++cfg->spill_count;
451 assign [i] = -spill - 1;
453 mono_regstate_free_float (cfg->rs, sel);
455 mono_regstate_free_int (cfg->rs, sel);
456 /* we need to create a spill var and insert a load to sel after the current instruction */
458 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
460 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
462 load->inst_basereg = cfg->frame_reg;
463 load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
464 MONO_INST_LIST_ADD_TAIL (&load->node, next);
465 DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
467 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
469 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
475 /* This isn't defined on older glib versions and on some platforms */
476 #ifndef G_GUINT64_FORMAT
477 #define G_GUINT64_FORMAT "ul"
481 get_register_spilling (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, regmask_t regmask, int reg, gboolean fp)
485 int *assign, *symbolic;
486 MonoRegState *rs = cfg->rs;
488 assign = cfg->rs->vassign;
490 symbolic = cfg->rs->fsymbolic;
492 symbolic = cfg->rs->isymbolic;
494 DEBUG (printf ("\tstart regmask to assign R%d: 0x%08" G_GUINT64_FORMAT " (R%d <- R%d R%d)\n", reg, (guint64)regmask, ins->dreg, ins->sreg1, ins->sreg2));
495 /* exclude the registers in the current instruction */
496 if ((sreg1_is_fp_ins (ins) == fp) && (reg != ins->sreg1) && (reg_is_freeable (ins->sreg1, fp) || (is_soft_reg (ins->sreg1, fp) && rs->vassign [ins->sreg1] >= 0))) {
497 if (is_soft_reg (ins->sreg1, fp))
498 regmask &= ~ (regmask (rs->vassign [ins->sreg1]));
500 regmask &= ~ (regmask (ins->sreg1));
501 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
503 if ((sreg2_is_fp_ins (ins) == fp) && (reg != ins->sreg2) && (reg_is_freeable (ins->sreg2, fp) || (is_soft_reg (ins->sreg2, fp) && rs->vassign [ins->sreg2] >= 0))) {
504 if (is_soft_reg (ins->sreg2, fp))
505 regmask &= ~ (regmask (rs->vassign [ins->sreg2]));
507 regmask &= ~ (regmask (ins->sreg2));
508 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
510 if ((dreg_is_fp_ins (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
511 regmask &= ~ (regmask (ins->dreg));
512 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
515 DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
516 g_assert (regmask); /* need at least a register we can free */
518 /* we should track prev_use and spill the register that's farther */
520 for (i = 0; i < MONO_MAX_FREGS; ++i) {
521 if (regmask & (regmask (i))) {
523 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
528 i = cfg->rs->fsymbolic [sel];
529 spill = ++cfg->spill_count;
530 cfg->rs->vassign [i] = -spill - 1;
531 mono_regstate_free_float (cfg->rs, sel);
534 for (i = 0; i < MONO_MAX_IREGS; ++i) {
535 if (regmask & (regmask (i))) {
537 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
542 i = cfg->rs->isymbolic [sel];
543 spill = ++cfg->spill_count;
544 cfg->rs->vassign [i] = -spill - 1;
545 mono_regstate_free_int (cfg->rs, sel);
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);
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)));
556 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
558 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
565 free_up_ireg (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, int hreg)
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);
575 free_up_reg (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, int hreg, gboolean 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);
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);
593 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins, const unsigned char *ip, gboolean fp)
598 MONO_INST_NEW (cfg, copy, OP_FMOVE);
600 MONO_INST_NEW (cfg, copy, OP_MOVE);
606 MONO_INST_LIST_ADD (©->node, &ins->node);
607 copy->cil_code = ins->cil_code;
609 DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
614 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins, gboolean fp)
617 MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
619 store->inst_destbasereg = cfg->frame_reg;
620 store->inst_offset = mono_spillvar_offset (cfg, spill, fp);
622 MONO_INST_LIST_ADD (&store->node, &ins->node);
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)));
628 /* flags used in reginfo->flags */
630 MONO_FP_NEEDS_LOAD_SPILL = regmask (0),
631 MONO_FP_NEEDS_SPILL = regmask (1),
632 MONO_FP_NEEDS_LOAD = regmask (2)
636 alloc_int_reg (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, regmask_t dest_mask, int sym_reg, RegTrack *info)
640 if (info && info->preferred_mask) {
641 val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
643 DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
648 val = mono_regstate_alloc_int (cfg->rs, dest_mask);
650 val = get_register_spilling (cfg, ins, next, dest_mask, sym_reg, FALSE);
656 alloc_float_reg (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, regmask_t dest_mask, int sym_reg)
660 val = mono_regstate_alloc_float (cfg->rs, dest_mask);
663 val = get_register_spilling (cfg, ins, next, dest_mask, sym_reg, TRUE);
670 alloc_reg (MonoCompile *cfg, MonoInst *ins, MonoInstList *next, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
673 return alloc_float_reg (cfg, ins, next, dest_mask, sym_reg);
675 return alloc_int_reg (cfg, ins, next, dest_mask, sym_reg, info);
679 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
682 g_assert (reg >= MONO_MAX_FREGS);
683 g_assert (hreg < MONO_MAX_FREGS);
684 g_assert (! is_global_freg (hreg));
686 rs->vassign [reg] = hreg;
687 rs->fsymbolic [hreg] = reg;
688 rs->ffree_mask &= ~ (regmask (hreg));
691 g_assert (reg >= MONO_MAX_IREGS);
692 g_assert (hreg < MONO_MAX_IREGS);
694 /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */
695 g_assert (! is_global_ireg (hreg));
698 rs->vassign [reg] = hreg;
699 rs->isymbolic [hreg] = reg;
700 rs->ifree_mask &= ~ (regmask (hreg));
705 assign_ireg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg)
707 assign_reg (cfg, rs, reg, hreg, FALSE);
711 * Local register allocation.
712 * We first scan the list of instructions and we save the liveness info of
713 * each register (when the register is first used, when it's value is set etc.).
716 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
719 MonoRegState *rs = cfg->rs;
723 GList *fspill_list = NULL;
726 #if MONO_ARCH_USE_FPSTACK
727 gboolean need_fpstack = use_fpstack;
730 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
733 rs->next_vreg = bb->max_vreg;
734 mono_regstate_assign (rs);
736 rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
737 rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
740 rs->ffree_mask = 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE));
742 if (cfg->reginfo && cfg->reginfo_len < rs->next_vreg) {
745 reginfo = cfg->reginfo;
747 cfg->reginfo_len = MAX (256, rs->next_vreg * 2);
748 reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
751 g_assert (cfg->reginfo_len >= rs->next_vreg);
753 memset (reginfo, 0, rs->next_vreg * sizeof (RegTrack));
757 DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb->block_num));
758 /* forward pass on the instructions to collect register liveness info */
759 MONO_BB_FOR_EACH_INS (bb, ins) {
760 spec = ins_get_spec (ins->opcode);
762 if (G_UNLIKELY (spec == MONO_ARCH_CPU_SPEC)) {
763 g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
766 DEBUG (mono_print_ins_index (i, ins));
771 #if MONO_ARCH_USE_FPSTACK
775 if (spec [MONO_INST_SRC1] == 'f') {
776 spill = g_list_first (fspill_list);
777 if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
778 reginfo [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
779 fspill_list = g_list_remove (fspill_list, spill->data);
784 if (spec [MONO_INST_SRC2] == 'f') {
785 spill = g_list_first (fspill_list);
787 reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
788 fspill_list = g_list_remove (fspill_list, spill->data);
789 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
791 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
792 reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
798 if (dreg_is_fp (spec)) {
799 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
800 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
801 reginfo [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
803 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
812 if (spec [MONO_INST_SRC1]) {
813 //reginfo [ins->sreg1].prev_use = reginfo [ins->sreg1].last_use;
814 //reginfo [ins->sreg1].last_use = i;
815 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
816 /* The virtual register is allocated sequentially */
817 //reginfo [ins->sreg1 + 1].prev_use = reginfo [ins->sreg1 + 1].last_use;
818 //reginfo [ins->sreg1 + 1].last_use = i;
819 if (reginfo [ins->sreg1 + 1].born_in == 0 || reginfo [ins->sreg1 + 1].born_in > i)
820 reginfo [ins->sreg1 + 1].born_in = i;
825 if (spec [MONO_INST_SRC2]) {
826 //reginfo [ins->sreg2].prev_use = reginfo [ins->sreg2].last_use;
827 //reginfo [ins->sreg2].last_use = i;
828 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
829 /* The virtual register is allocated sequentially */
830 //reginfo [ins->sreg2 + 1].prev_use = reginfo [ins->sreg2 + 1].last_use;
831 //reginfo [ins->sreg2 + 1].last_use = i;
832 if (reginfo [ins->sreg2 + 1].born_in == 0 || reginfo [ins->sreg2 + 1].born_in > i)
833 reginfo [ins->sreg2 + 1].born_in = i;
838 if (spec [MONO_INST_DEST]) {
841 if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
842 reginfo [ins->dreg].killed_in = i;
843 //reginfo [ins->dreg].prev_use = reginfo [ins->dreg].last_use;
844 //reginfo [ins->dreg].last_use = i;
845 if (reginfo [ins->dreg].born_in == 0 || reginfo [ins->dreg].born_in > i)
846 reginfo [ins->dreg].born_in = i;
848 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
850 reginfo [ins->dreg].preferred_mask = (regmask (dest_dreg));
852 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
853 /* The virtual register is allocated sequentially */
854 //reginfo [ins->dreg + 1].prev_use = reginfo [ins->dreg + 1].last_use;
855 //reginfo [ins->dreg + 1].last_use = i;
856 if (reginfo [ins->dreg + 1].born_in == 0 || reginfo [ins->dreg + 1].born_in > i)
857 reginfo [ins->dreg + 1].born_in = i;
858 if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
859 reginfo [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
865 if (spec [MONO_INST_CLOB] == 'c') {
866 /* A call instruction implicitly uses all registers in call->out_ireg_args */
868 MonoCallInst *call = (MonoCallInst*)ins;
871 list = call->out_ireg_args;
877 regpair = (guint32)(gssize)(list->data);
878 hreg = regpair >> 24;
879 reg = regpair & 0xffffff;
881 //reginfo [reg].prev_use = reginfo [reg].last_use;
882 //reginfo [reg].last_use = i;
884 list = g_slist_next (list);
888 list = call->out_freg_args;
889 if (!use_fpstack && list) {
894 regpair = (guint32)(gssize)(list->data);
895 hreg = regpair >> 24;
896 reg = regpair & 0xffffff;
898 //reginfo [reg].prev_use = reginfo [reg].last_use;
899 //reginfo [reg].last_use = i;
901 list = g_slist_next (list);
909 // todo: check if we have anything left on fp stack, in verify mode?
912 DEBUG (print_regtrack (reginfo, rs->next_vreg));
913 ins = mono_inst_list_last (&bb->ins_list);
915 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
916 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
917 int dreg_high, sreg1_high;
918 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
919 regmask_t dreg_fixed_mask, sreg1_fixed_mask, sreg2_fixed_mask;
920 const unsigned char *ip;
924 prev_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
925 next = ins->node.next;
928 spec = ins_get_spec (ins->opcode);
939 dreg_mask = dreg_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
940 sreg1_mask = sreg1_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
941 sreg2_mask = sreg2_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
943 DEBUG (printf ("processing:"));
944 DEBUG (mono_print_ins_index (i, ins));
951 dest_sreg1 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC1]);
952 dest_sreg2 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC2]);
953 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
954 clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
955 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
957 #ifdef MONO_ARCH_INST_FIXED_MASK
958 sreg1_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC1]);
959 sreg2_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC2]);
960 dreg_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_DEST]);
962 sreg1_fixed_mask = sreg2_fixed_mask = dreg_fixed_mask = 0;
968 #if MONO_ARCH_USE_FPSTACK
969 if (need_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
970 if (dreg_is_fp (spec)) {
971 if (reginfo [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
974 spill_node = g_list_first (fspill_list);
975 g_assert (spill_node);
977 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
978 insert_before_ins (ins, store);
979 fspill_list = g_list_remove (fspill_list, spill_node->data);
984 if (spec [MONO_INST_SRC1] == 'f') {
985 if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
987 MonoInst *store = NULL;
989 if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
991 spill_node = g_list_first (fspill_list);
992 g_assert (spill_node);
994 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);
995 fspill_list = g_list_remove (fspill_list, spill_node->data);
999 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1000 load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
1001 insert_before_ins (ins, load);
1003 insert_before_ins (load, store);
1007 if (spec [MONO_INST_SRC2] == 'f') {
1008 if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
1010 MonoInst *store = NULL;
1012 if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1015 spill_node = g_list_first (fspill_list);
1016 g_assert (spill_node);
1017 if (spec [MONO_INST_SRC1] == 'f' && (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
1018 spill_node = g_list_next (spill_node);
1020 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
1021 fspill_list = g_list_remove (fspill_list, spill_node->data);
1025 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1026 load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
1027 insert_before_ins (ins, load);
1029 insert_before_ins (load, store);
1038 if (dest_sreg2 != -1) {
1039 if (rs->ifree_mask & (regmask (dest_sreg2))) {
1040 if (is_global_ireg (ins->sreg2)) {
1041 /* Argument already in hard reg, need to copy */
1042 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1043 insert_before_ins (ins, copy);
1046 val = rs->vassign [ins->sreg2];
1048 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
1049 assign_reg (cfg, rs, ins->sreg2, dest_sreg2, FALSE);
1050 } else if (val < -1) {
1052 g_assert_not_reached ();
1054 /* Argument already in hard reg, need to copy */
1055 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, val, NULL, ip, FALSE);
1056 insert_before_ins (ins, copy);
1060 int need_spill = TRUE;
1062 dreg_mask &= ~ (regmask (dest_sreg2));
1063 sreg1_mask &= ~ (regmask (dest_sreg2));
1066 * First check if dreg is assigned to dest_sreg2, since we
1067 * can't spill a dreg.
1069 val = rs->vassign [ins->dreg];
1070 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
1072 * the destination register is already assigned to
1073 * dest_sreg2: we need to allocate another register for it
1074 * and then copy from this to dest_sreg2.
1077 new_dest = alloc_int_reg (cfg, ins, next, dreg_mask, ins->dreg, ®info [ins->dreg]);
1078 g_assert (new_dest >= 0);
1079 DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
1081 prev_dreg = ins->dreg;
1082 assign_ireg (cfg, rs, ins->dreg, new_dest);
1083 clob_dreg = ins->dreg;
1084 create_copy_ins (cfg, dest_sreg2, new_dest, ins, ip, FALSE);
1085 mono_regstate_free_int (rs, dest_sreg2);
1089 if (is_global_ireg (ins->sreg2)) {
1090 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1091 insert_before_ins (ins, copy);
1094 val = rs->vassign [ins->sreg2];
1095 if (val == dest_sreg2) {
1096 /* sreg2 is already assigned to the correct register */
1099 else if ((val >= 0) || (val < -1)) {
1100 /* FIXME: sreg2 already assigned to another register */
1101 g_assert_not_reached ();
1106 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1107 get_register_force_spilling (cfg, ins, next, rs->isymbolic [dest_sreg2], FALSE);
1108 mono_regstate_free_int (rs, dest_sreg2);
1111 if (!is_global_ireg (ins->sreg2))
1112 /* force-set sreg2 */
1113 assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1115 ins->sreg2 = dest_sreg2;
1121 fp = dreg_is_fp (spec);
1122 if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
1123 prev_dreg = ins->dreg;
1125 if (spec [MONO_INST_DEST] == 'b') {
1127 * The dest reg is read by the instruction, not written, so
1128 * avoid allocating sreg1/sreg2 to the same reg.
1130 if (dest_sreg1 != -1)
1131 dreg_mask &= ~ (regmask (dest_sreg1));
1132 if (dest_sreg2 != -1)
1133 dreg_mask &= ~ (regmask (dest_sreg2));
1135 val = rs->vassign [ins->dreg];
1136 if (is_soft_reg (ins->dreg, fp) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
1137 /* DREG is already allocated to a register needed for sreg1 */
1138 get_register_force_spilling (cfg, ins, next, ins->dreg, FALSE);
1139 mono_regstate_free_int (rs, val);
1144 * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1145 * various complex situations.
1147 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1148 guint32 dreg2, dest_dreg2;
1150 g_assert (is_soft_reg (ins->dreg, fp));
1152 if (dest_dreg != -1) {
1153 if (rs->vassign [ins->dreg] != dest_dreg)
1154 free_up_ireg (cfg, ins, next, dest_dreg);
1156 dreg2 = ins->dreg + 1;
1157 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
1158 if (dest_dreg2 != -1) {
1159 if (rs->vassign [dreg2] != dest_dreg2)
1160 free_up_ireg (cfg, ins, next, dest_dreg2);
1165 if (dreg_fixed_mask) {
1167 if (is_global_ireg (ins->dreg)) {
1169 * The argument is already in a hard reg, but that reg is
1170 * not usable by this instruction, so allocate a new one.
1172 val = mono_regstate_alloc_int (rs, dreg_fixed_mask);
1174 val = get_register_spilling (cfg, ins, next, dreg_fixed_mask, -1, fp);
1175 mono_regstate_free_int (rs, val);
1181 dreg_mask &= dreg_fixed_mask;
1184 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
1185 if (dest_dreg != -1)
1186 dreg_mask = (regmask (dest_dreg));
1188 val = rs->vassign [ins->dreg];
1193 /* the register gets spilled after this inst */
1196 val = alloc_reg (cfg, ins, next, dreg_mask, ins->dreg, ®info [ins->dreg], fp);
1197 assign_reg (cfg, rs, ins->dreg, val, fp);
1199 create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
1202 DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
1206 /* Handle regpairs */
1207 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1208 int reg2 = prev_dreg + 1;
1211 g_assert (prev_dreg > -1);
1212 g_assert (!is_global_ireg (rs->vassign [prev_dreg]));
1213 mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->vassign [prev_dreg]);
1216 mask &= ~regmask (X86_ECX);
1218 val = rs->vassign [reg2];
1222 /* the register gets spilled after this inst */
1225 val = mono_regstate_alloc_int (rs, mask);
1227 val = get_register_spilling (cfg, ins, next, mask, reg2, fp);
1229 create_spilled_store (cfg, spill, val, reg2, ins, fp);
1232 if (! (mask & (regmask (val)))) {
1233 val = mono_regstate_alloc_int (rs, mask);
1235 val = get_register_spilling (cfg, ins, next, mask, reg2, fp);
1237 /* Reallocate hreg to the correct register */
1238 create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
1240 mono_regstate_free_int (rs, rs->vassign [reg2]);
1244 DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1245 assign_reg (cfg, rs, reg2, val, fp);
1248 ins->backend.reg3 = val;
1250 if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1251 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1252 mono_regstate_free_int (rs, val);
1256 if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && reginfo [prev_dreg].born_in >= i) {
1258 * In theory, we could free up the hreg even if the vreg is alive,
1259 * but branches inside bblocks force us to assign the same hreg
1260 * to a vreg every time it is encountered.
1262 int dreg = rs->vassign [prev_dreg];
1263 g_assert (dreg >= 0);
1264 DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, reginfo [prev_dreg].born_in));
1266 mono_regstate_free_float (rs, dreg);
1268 mono_regstate_free_int (rs, dreg);
1271 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1272 /* this instruction only outputs to dest_dreg, need to copy */
1273 create_copy_ins (cfg, ins->dreg, dest_dreg, ins, ip, fp);
1274 ins->dreg = dest_dreg;
1277 if (rs->fsymbolic [dest_dreg] >= MONO_MAX_FREGS)
1278 free_up_reg (cfg, ins, next, dest_dreg, fp);
1281 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1282 free_up_reg (cfg, ins, next, dest_dreg, fp);
1286 if (spec [MONO_INST_DEST] == 'b') {
1288 * The dest reg is read by the instruction, not written, so
1289 * avoid allocating sreg1/sreg2 to the same reg.
1291 sreg1_mask &= ~ (regmask (ins->dreg));
1292 sreg2_mask &= ~ (regmask (ins->dreg));
1298 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1299 DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1300 get_register_force_spilling (cfg, ins, next, rs->isymbolic [clob_reg], FALSE);
1301 mono_regstate_free_int (rs, clob_reg);
1304 if (spec [MONO_INST_CLOB] == 'c') {
1305 int j, s, dreg, dreg2;
1308 clob_mask = MONO_ARCH_CALLEE_REGS;
1311 * Need to avoid spilling the dreg since the dreg is not really
1312 * clobbered by the call.
1314 if ((prev_dreg != -1) && !dreg_is_fp (spec))
1315 dreg = rs->vassign [prev_dreg];
1319 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
1320 dreg2 = rs->vassign [prev_dreg + 1];
1324 for (j = 0; j < MONO_MAX_IREGS; ++j) {
1326 if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
1327 get_register_force_spilling (cfg, ins, next, rs->isymbolic [j], FALSE);
1328 mono_regstate_free_int (rs, j);
1333 clob_mask = MONO_ARCH_CALLEE_FREGS;
1334 if ((prev_dreg != -1) && dreg_is_fp (spec))
1335 dreg = rs->vassign [prev_dreg];
1339 for (j = 0; j < MONO_MAX_FREGS; ++j) {
1341 if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
1342 get_register_force_spilling (cfg, ins, next, rs->fsymbolic [j], TRUE);
1343 mono_regstate_free_float (rs, j);
1350 * TRACK ARGUMENT REGS
1352 if (spec [MONO_INST_CLOB] == 'c') {
1353 MonoCallInst *call = (MonoCallInst*)ins;
1357 * This needs to be done before assigning sreg1, so sreg1 will
1358 * not be assigned one of the argument regs.
1362 * Assign all registers in call->out_reg_args to the proper
1363 * argument registers.
1366 list = call->out_ireg_args;
1372 regpair = (guint32)(gssize)(list->data);
1373 hreg = regpair >> 24;
1374 reg = regpair & 0xffffff;
1376 assign_reg (cfg, rs, reg, hreg, FALSE);
1378 sreg1_mask &= ~(regmask (hreg));
1380 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1382 list = g_slist_next (list);
1386 list = call->out_freg_args;
1387 if (list && !use_fpstack) {
1392 regpair = (guint32)(gssize)(list->data);
1393 hreg = regpair >> 24;
1394 reg = regpair & 0xffffff;
1396 assign_reg (cfg, rs, reg, hreg, TRUE);
1398 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
1400 list = g_slist_next (list);
1408 fp = sreg1_is_fp (spec);
1409 if ((!fp || (fp && !use_fpstack))) {
1410 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
1411 g_assert (is_soft_reg (ins->sreg1, fp));
1413 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1414 if (dest_sreg1 != -1)
1415 g_assert (dest_sreg1 == ins->dreg);
1416 val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
1417 g_assert (val >= 0);
1418 assign_reg (cfg, rs, ins->sreg1, val, fp);
1420 DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1422 g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
1423 val = mono_regstate_alloc_int (rs, regmask (dreg_high));
1424 g_assert (val >= 0);
1425 assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
1427 DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
1429 /* Skip rest of this section */
1433 if (sreg1_fixed_mask) {
1435 if (is_global_ireg (ins->sreg1)) {
1437 * The argument is already in a hard reg, but that reg is
1438 * not usable by this instruction, so allocate a new one.
1440 val = mono_regstate_alloc_int (rs, sreg1_fixed_mask);
1442 val = get_register_spilling (cfg, ins, next, sreg1_fixed_mask, -1, fp);
1443 mono_regstate_free_int (rs, val);
1446 /* Fall through to the dest_sreg1 != -1 case */
1449 sreg1_mask &= sreg1_fixed_mask;
1452 if (dest_sreg1 != -1) {
1453 sreg1_mask = regmask (dest_sreg1);
1455 if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
1456 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1457 get_register_force_spilling (cfg, ins, next, rs->isymbolic [dest_sreg1], FALSE);
1458 mono_regstate_free_int (rs, dest_sreg1);
1460 if (is_global_ireg (ins->sreg1)) {
1461 /* The argument is already in a hard reg, need to copy */
1462 MonoInst *copy = create_copy_ins (cfg, dest_sreg1, ins->sreg1, NULL, ip, FALSE);
1463 insert_before_ins (ins, copy);
1464 ins->sreg1 = dest_sreg1;
1468 if (is_soft_reg (ins->sreg1, fp)) {
1469 val = rs->vassign [ins->sreg1];
1470 prev_sreg1 = ins->sreg1;
1474 /* the register gets spilled after this inst */
1478 if ((ins->opcode == OP_MOVE) && !spill && !fp && (is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
1480 * Allocate the same hreg to sreg1 as well so the
1481 * peephole can get rid of the move.
1483 sreg1_mask = regmask (ins->dreg);
1486 val = alloc_reg (cfg, ins, next, sreg1_mask, ins->sreg1, ®info [ins->sreg1], fp);
1487 assign_reg (cfg, rs, ins->sreg1, val, fp);
1488 DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1491 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
1493 * Need to insert before the instruction since it can
1496 insert_before_ins (ins, store);
1499 else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1500 create_copy_ins (cfg, dest_sreg1, val, ins, ip, fp);
1508 sreg2_mask &= ~(regmask (ins->sreg1));
1511 /* Handle the case when sreg1 is a regpair but dreg is not */
1512 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1]) && (spec [MONO_INST_CLOB] != '1')) {
1513 int reg2 = prev_sreg1 + 1;
1516 g_assert (prev_sreg1 > -1);
1517 g_assert (!is_global_ireg (rs->vassign [prev_sreg1]));
1518 mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->vassign [prev_sreg1]);
1519 val = rs->vassign [reg2];
1523 /* the register gets spilled after this inst */
1526 val = mono_regstate_alloc_int (rs, mask);
1528 val = get_register_spilling (cfg, ins, next, mask, reg2, fp);
1530 g_assert_not_reached ();
1533 if (! (mask & (regmask (val)))) {
1534 /* The vreg is already allocated to a wrong hreg */
1536 g_assert_not_reached ();
1538 val = mono_regstate_alloc_int (rs, mask);
1540 val = get_register_spilling (cfg, ins, next, mask, reg2, fp);
1542 /* Reallocate hreg to the correct register */
1543 create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
1545 mono_regstate_free_int (rs, rs->vassign [reg2]);
1551 DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1552 assign_reg (cfg, rs, reg2, val, fp);
1555 /* Handle dreg==sreg1 */
1556 if (((dreg_is_fp (spec) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1557 MonoInst *sreg2_copy = NULL;
1559 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
1561 if (ins->dreg == ins->sreg2) {
1563 * copying sreg1 to dreg could clobber sreg2, so allocate a new
1566 int reg2 = alloc_reg (cfg, ins, next, dreg_mask, ins->sreg2, NULL, fp);
1568 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
1569 sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
1570 prev_sreg2 = ins->sreg2 = reg2;
1573 mono_regstate_free_float (rs, reg2);
1575 mono_regstate_free_int (rs, reg2);
1578 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
1579 /* Copying sreg1_high to dreg could also clobber sreg2 */
1580 if (rs->vassign [prev_sreg1 + 1] == ins->sreg2)
1582 g_assert_not_reached ();
1585 * sreg1 and dest are already allocated to the same regpair by the
1586 * SREG1 allocation code.
1588 g_assert (ins->sreg1 == ins->dreg);
1589 g_assert (dreg_high == sreg1_high);
1592 DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
1593 copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
1594 insert_before_ins (ins, copy);
1597 insert_before_ins (copy, sreg2_copy);
1600 * Need to prevent sreg2 to be allocated to sreg1, since that
1601 * would screw up the previous copy.
1603 sreg2_mask &= ~ (regmask (ins->sreg1));
1604 /* we set sreg1 to dest as well */
1605 prev_sreg1 = ins->sreg1 = ins->dreg;
1606 sreg2_mask &= ~ (regmask (ins->dreg));
1612 fp = sreg2_is_fp (spec);
1613 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
1614 g_assert_not_reached ();
1615 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
1616 val = rs->vassign [ins->sreg2];
1621 /* the register gets spilled after this inst */
1624 val = alloc_reg (cfg, ins, next, sreg2_mask, ins->sreg2, ®info [ins->sreg2], fp);
1625 assign_reg (cfg, rs, ins->sreg2, val, fp);
1626 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
1628 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg2, NULL, fp);
1630 * Need to insert before the instruction since it can
1633 insert_before_ins (ins, store);
1642 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1643 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1644 mono_regstate_free_int (rs, ins->sreg1);
1646 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1647 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1648 mono_regstate_free_int (rs, ins->sreg2);
1651 DEBUG (mono_print_ins_index (i, ins));
1655 g_list_free (fspill_list);
1659 mono_opcode_to_cond (int opcode)
1670 case OP_COND_EXC_EQ:
1671 case OP_COND_EXC_IEQ:
1677 case OP_COND_EXC_NE_UN:
1678 case OP_COND_EXC_INE_UN:
1698 case OP_COND_EXC_LT:
1699 case OP_COND_EXC_ILT:
1709 case OP_COND_EXC_GT:
1710 case OP_COND_EXC_IGT:
1717 case OP_COND_EXC_LE_UN:
1718 case OP_COND_EXC_ILE_UN:
1733 case OP_COND_EXC_LT_UN:
1734 case OP_COND_EXC_ILT_UN:
1744 case OP_COND_EXC_GT_UN:
1745 case OP_COND_EXC_IGT_UN:
1748 printf ("%s\n", mono_inst_name (opcode));
1749 g_assert_not_reached ();
1755 mono_opcode_to_type (int opcode, int cmp_opcode)
1757 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1759 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1761 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLT_UN))
1763 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1765 else if ((opcode >= OP_LBEQ) && (opcode <= OP_LBLT_UN))
1767 else if ((opcode >= OP_LCEQ) && (opcode <= OP_LCLT_UN))
1769 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLT_UN))
1771 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1773 else if ((opcode >= OP_COND_EXC_IEQ) && (opcode <= OP_COND_EXC_ILT_UN))
1775 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1776 switch (cmp_opcode) {
1778 case OP_ICOMPARE_IMM:
1784 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1790 mono_is_regsize_var (MonoType *t)
1794 t = mono_type_get_underlying_type (t);
1796 case MONO_TYPE_BOOLEAN:
1797 case MONO_TYPE_CHAR:
1807 case MONO_TYPE_FNPTR:
1808 #if SIZEOF_VOID_P == 8
1813 case MONO_TYPE_OBJECT:
1814 case MONO_TYPE_STRING:
1815 case MONO_TYPE_CLASS:
1816 case MONO_TYPE_SZARRAY:
1817 case MONO_TYPE_ARRAY:
1819 case MONO_TYPE_GENERICINST:
1820 if (!mono_type_generic_inst_is_valuetype (t))
1823 case MONO_TYPE_VALUETYPE: