2 * mini-codegen.c: Arch independent code generation functionality
4 * (C) 2003 Ximian, Inc.
11 #include <mono/metadata/appdomain.h>
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/threads.h>
14 #include <mono/metadata/profiler-private.h>
15 #include <mono/utils/mono-math.h>
20 #include "mini-arch.h"
22 #define DEBUG(a) if (cfg->verbose_level > 1) a
24 #if defined(__x86_64__)
25 const char * const amd64_desc [OP_LAST];
26 static const char*const * ins_spec = amd64_desc;
27 #elif defined(__sparc__) || defined(sparc)
28 const char * const sparc_desc [OP_LAST];
29 static const char*const * ins_spec = sparc_desc;
30 #elif defined(__i386__)
31 extern const char * const pentium_desc [OP_LAST];
32 static const char*const * ins_spec = pentium_desc;
33 #elif defined(__ia64__)
34 const char * const ia64_desc [OP_LAST];
35 static const char*const * ins_spec = ia64_desc;
36 #elif defined(__arm__)
37 const char * const arm_cpu_desc [OP_LAST];
38 static const char*const * ins_spec = arm_cpu_desc;
39 #elif defined(__s390x__)
40 const char * const s390x_cpu_desc [OP_LAST];
41 static const char*const * ins_spec = s390x_cpu_desc;
42 #elif defined(__s390__)
43 const char * const s390_cpu_desc [OP_LAST];
44 static const char*const * ins_spec = s390_cpu_desc;
46 #error "Not implemented"
49 #define use_fpstack MONO_ARCH_USE_FPSTACK
52 mono_regname_full (int reg, gboolean fp)
55 return mono_arch_fregname (reg);
57 return mono_arch_regname (reg);
61 mono_call_inst_add_outarg_reg (MonoCallInst *call, int vreg, int hreg, gboolean fp)
65 regpair = (((guint32)hreg) << 24) + vreg;
67 call->out_freg_args = g_slist_append (call->out_freg_args, (gpointer)(gssize)(regpair));
69 call->out_ireg_args = g_slist_append (call->out_ireg_args, (gpointer)(gssize)(regpair));
73 * returns the offset used by spillvar. It allocates a new
74 * spill variable if necessary.
77 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
79 MonoSpillInfo **si, *info;
82 si = &cfg->spill_info;
84 while (i <= spillvar) {
87 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
89 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
90 info->offset = cfg->stack_offset;
91 cfg->stack_offset += sizeof (gpointer);
93 cfg->stack_offset += sizeof (gpointer);
94 info->offset = - cfg->stack_offset;
105 g_assert_not_reached ();
110 * returns the offset used by spillvar. It allocates a new
111 * spill float variable if necessary.
112 * (same as mono_spillvar_offset but for float)
115 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
117 MonoSpillInfo **si, *info;
120 si = &cfg->spill_info_float;
122 while (i <= spillvar) {
125 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
127 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
128 cfg->stack_offset += 7;
129 cfg->stack_offset &= ~7;
130 info->offset = cfg->stack_offset;
131 cfg->stack_offset += sizeof (double);
134 cfg->stack_offset += sizeof (double);
135 info->offset = - cfg->stack_offset;
140 return (*si)->offset;
146 g_assert_not_reached ();
151 * Creates a store for spilled floating point items
154 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
157 MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
159 store->inst_destbasereg = cfg->frame_reg;
160 store->inst_offset = mono_spillvar_offset_float (cfg, spill);
162 DEBUG (g_print ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
167 * Creates a load for spilled floating point items
170 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
173 MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
175 load->inst_basereg = cfg->frame_reg;
176 load->inst_offset = mono_spillvar_offset_float (cfg, spill);
178 DEBUG (g_print ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
182 #define regmask(reg) (((regmask_t)1) << (reg))
184 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
185 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
186 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
187 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
188 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
189 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
190 #define ireg_is_freeable(r) is_local_ireg ((r))
191 #define freg_is_freeable(r) is_hard_freg ((r))
193 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
194 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
195 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
196 #define rassign(cfg,reg,fp) ((fp) ? (cfg)->rs->fassign [(reg)] : (cfg)->rs->iassign [(reg)])
197 #define sreg1_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_SRC1] == 'f')
198 #define sreg2_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_SRC2] == 'f')
200 #ifdef MONO_ARCH_INST_IS_FLOAT
201 #define dreg_is_fp(ins) (MONO_ARCH_INST_IS_FLOAT (ins_spec [(ins)->opcode] [MONO_INST_DEST]))
203 #define dreg_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_DEST] == 'f')
206 #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)
208 #ifdef MONO_ARCH_IS_GLOBAL_IREG
209 #undef is_global_ireg
210 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
218 int flags; /* used to track fp spill/load */
219 regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
223 print_ins (int i, MonoInst *ins)
225 const char *spec = ins_spec [ins->opcode];
226 g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
228 g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
230 if (spec [MONO_INST_DEST]) {
231 gboolean fp = dreg_is_fp (ins);
232 if (is_soft_reg (ins->dreg, fp)) {
233 if (spec [MONO_INST_DEST] == 'b') {
234 if (ins->inst_offset == 0)
235 g_print (" [R%d] <-", ins->dreg);
237 g_print (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
240 g_print (" R%d <-", ins->dreg);
241 } else if (spec [MONO_INST_DEST] == 'b') {
242 if (ins->inst_offset == 0)
243 g_print (" [%s] <-", mono_arch_regname (ins->dreg));
245 g_print (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
247 g_print (" %s <-", mono_regname_full (ins->dreg, fp));
249 if (spec [MONO_INST_SRC1]) {
250 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
251 if (is_soft_reg (ins->sreg1, fp))
252 g_print (" R%d", ins->sreg1);
253 else if (spec [MONO_INST_SRC1] == 'b')
254 g_print (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
256 g_print (" %s", mono_regname_full (ins->sreg1, fp));
258 if (spec [MONO_INST_SRC2]) {
259 gboolean fp = (spec [MONO_INST_SRC2] == 'f');
260 if (is_soft_reg (ins->sreg2, fp))
261 g_print (" R%d", ins->sreg2);
263 g_print (" %s", mono_regname_full (ins->sreg2, fp));
265 if (spec [MONO_INST_CLOB])
266 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
271 print_regtrack (RegTrack *t, int num)
277 for (i = 0; i < num; ++i) {
280 if (i >= MONO_MAX_IREGS) {
281 g_snprintf (buf, sizeof(buf), "R%d", i);
284 r = mono_arch_regname (i);
285 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
289 typedef struct InstList InstList;
297 static inline InstList*
298 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
300 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
310 * Force the spilling of the variable in the symbolic register 'reg'.
313 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg, gboolean fp)
317 int *assign, *symbolic;
320 assign = cfg->rs->fassign;
321 symbolic = cfg->rs->fsymbolic;
324 assign = cfg->rs->iassign;
325 symbolic = cfg->rs->isymbolic;
329 /*i = cfg->rs->isymbolic [sel];
330 g_assert (i == reg);*/
332 spill = ++cfg->spill_count;
333 assign [i] = -spill - 1;
335 mono_regstate_free_float (cfg->rs, sel);
337 mono_regstate_free_int (cfg->rs, sel);
338 /* we need to create a spill var and insert a load to sel after the current instruction */
340 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
342 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
344 load->inst_basereg = cfg->frame_reg;
345 load->inst_offset = mono_spillvar_offset (cfg, spill);
347 while (ins->next != item->prev->data)
350 load->next = ins->next;
352 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
354 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
356 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
362 /* This isn't defined on older glib versions and on some platforms */
363 #ifndef G_GUINT64_FORMAT
364 #define G_GUINT64_FORMAT "ul"
368 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_t regmask, int reg, gboolean fp)
372 int *assign, *symbolic;
375 assign = cfg->rs->fassign;
376 symbolic = cfg->rs->fsymbolic;
379 assign = cfg->rs->iassign;
380 symbolic = cfg->rs->isymbolic;
383 DEBUG (g_print ("\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));
384 /* exclude the registers in the current instruction */
385 if ((sreg1_is_fp (ins) == fp) && (reg != ins->sreg1) && (reg_is_freeable (ins->sreg1, fp) || (is_soft_reg (ins->sreg1, fp) && rassign (cfg, ins->sreg1, fp) >= 0))) {
386 if (is_soft_reg (ins->sreg1, fp))
387 regmask &= ~ (regmask (rassign (cfg, ins->sreg1, fp)));
389 regmask &= ~ (regmask (ins->sreg1));
390 DEBUG (g_print ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
392 if ((sreg2_is_fp (ins) == fp) && (reg != ins->sreg2) && (reg_is_freeable (ins->sreg2, fp) || (is_soft_reg (ins->sreg2, fp) && rassign (cfg, ins->sreg2, fp) >= 0))) {
393 if (is_soft_reg (ins->sreg2, fp))
394 regmask &= ~ (regmask (rassign (cfg, ins->sreg2, fp)));
396 regmask &= ~ (regmask (ins->sreg2));
397 DEBUG (g_print ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
399 if ((dreg_is_fp (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
400 regmask &= ~ (regmask (ins->dreg));
401 DEBUG (g_print ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
404 DEBUG (g_print ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
405 g_assert (regmask); /* need at least a register we can free */
407 /* we should track prev_use and spill the register that's farther */
409 for (i = 0; i < MONO_MAX_FREGS; ++i) {
410 if (regmask & (regmask (i))) {
412 DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
417 i = cfg->rs->fsymbolic [sel];
418 spill = ++cfg->spill_count;
419 cfg->rs->fassign [i] = -spill - 1;
420 mono_regstate_free_float (cfg->rs, sel);
423 for (i = 0; i < MONO_MAX_IREGS; ++i) {
424 if (regmask & (regmask (i))) {
426 DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
431 i = cfg->rs->isymbolic [sel];
432 spill = ++cfg->spill_count;
433 cfg->rs->iassign [i] = -spill - 1;
434 mono_regstate_free_int (cfg->rs, sel);
437 /* we need to create a spill var and insert a load to sel after the current instruction */
438 MONO_INST_NEW (cfg, load, fp ? OP_LOADR8_MEMBASE : OP_LOAD_MEMBASE);
440 load->inst_basereg = cfg->frame_reg;
441 load->inst_offset = mono_spillvar_offset (cfg, spill);
443 while (ins->next != item->prev->data)
446 load->next = ins->next;
448 DEBUG (g_print ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
450 i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
452 i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
459 free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
461 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
462 DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
463 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
464 mono_regstate_free_int (cfg->rs, hreg);
469 free_up_reg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg, gboolean fp)
472 if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
473 DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
474 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
475 mono_regstate_free_float (cfg->rs, hreg);
479 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
480 DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
481 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
482 mono_regstate_free_int (cfg->rs, hreg);
488 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins, const unsigned char *ip, gboolean fp)
493 MONO_INST_NEW (cfg, copy, OP_FMOVE);
495 MONO_INST_NEW (cfg, copy, OP_MOVE);
501 copy->next = ins->next;
502 copy->cil_code = ins->cil_code;
505 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
510 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins, gboolean fp)
513 MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
515 store->inst_destbasereg = cfg->frame_reg;
516 store->inst_offset = mono_spillvar_offset (cfg, spill);
518 store->next = ins->next;
521 DEBUG (g_print ("\tSPILLED STORE (%d at 0x%08lx(%%ebp)) R%d (from %s)\n", spill, (long)store->inst_offset, prev_reg, mono_regname_full (reg, fp)));
526 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
530 prev = item->next->data;
532 while (prev->next != ins)
534 to_insert->next = ins;
535 prev->next = to_insert;
537 to_insert->next = ins;
540 * needed otherwise in the next instruction we can add an ins to the
541 * end and that would get past this instruction.
543 item->data = to_insert;
546 /* flags used in reginfo->flags */
548 MONO_FP_NEEDS_LOAD_SPILL = regmask (0),
549 MONO_FP_NEEDS_SPILL = regmask (1),
550 MONO_FP_NEEDS_LOAD = regmask (2)
554 alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
558 if (info && info->preferred_mask) {
559 val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
561 DEBUG (g_print ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
566 val = mono_regstate_alloc_int (cfg->rs, dest_mask);
568 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
574 alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg)
578 val = mono_regstate_alloc_float (cfg->rs, dest_mask);
581 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
588 alloc_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
591 return alloc_float_reg (cfg, tmp, ins, dest_mask, sym_reg);
593 return alloc_int_reg (cfg, tmp, ins, dest_mask, sym_reg, info);
597 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
600 g_assert (reg >= MONO_MAX_FREGS);
601 g_assert (hreg < MONO_MAX_FREGS);
602 g_assert (! is_global_freg (hreg));
604 rs->fassign [reg] = hreg;
605 rs->fsymbolic [hreg] = reg;
606 rs->ffree_mask &= ~ (regmask (hreg));
609 g_assert (reg >= MONO_MAX_IREGS);
610 g_assert (hreg < MONO_MAX_IREGS);
611 g_assert (! is_global_ireg (hreg));
613 rs->iassign [reg] = hreg;
614 rs->isymbolic [hreg] = reg;
615 rs->ifree_mask &= ~ (regmask (hreg));
620 assign_ireg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg)
622 assign_reg (cfg, rs, reg, hreg, FALSE);
626 * Local register allocation.
627 * We first scan the list of instructions and we save the liveness info of
628 * each register (when the register is first used, when it's value is set etc.).
629 * We also reverse the list of instructions (in the InstList list) because assigning
630 * registers backwards allows for more tricks to be used.
633 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
636 MonoRegState *rs = cfg->rs;
638 RegTrack *reginfo, *reginfof;
639 RegTrack *reginfo1, *reginfo2, *reginfod;
640 InstList *tmp, *reversed = NULL;
642 GList *fspill_list = NULL;
649 rs->next_vireg = bb->max_ireg;
650 rs->next_vfreg = bb->max_freg;
651 mono_regstate_assign (rs);
652 reginfo = g_malloc0 (sizeof (RegTrack) * rs->next_vireg);
653 reginfof = g_malloc0 (sizeof (RegTrack) * rs->next_vfreg);
654 rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
655 rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
658 rs->ffree_mask = 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE));
662 /*if (cfg->opt & MONO_OPT_COPYPROP)
663 local_copy_prop (cfg, ins);*/
667 DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
668 /* forward pass on the instructions to collect register liveness info */
670 spec = ins_spec [ins->opcode];
673 g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
676 DEBUG (print_ins (i, ins));
684 if (spec [MONO_INST_SRC1] == 'f') {
685 spill = g_list_first (fspill_list);
686 if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
687 reginfof [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
688 fspill_list = g_list_remove (fspill_list, spill->data);
693 if (spec [MONO_INST_SRC2] == 'f') {
694 spill = g_list_first (fspill_list);
696 reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
697 fspill_list = g_list_remove (fspill_list, spill->data);
698 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
700 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
701 reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
707 if (dreg_is_fp (ins)) {
708 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
709 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
710 reginfof [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
712 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
720 if (spec [MONO_INST_SRC1]) {
721 if (spec [MONO_INST_SRC1] == 'f')
725 reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
726 reginfo1 [ins->sreg1].last_use = i;
727 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
728 /* The virtual register is allocated sequentially */
729 reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
730 reginfo1 [ins->sreg1 + 1].last_use = i;
731 if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
732 reginfo1 [ins->sreg1 + 1].born_in = i;
737 if (spec [MONO_INST_SRC2]) {
738 if (spec [MONO_INST_SRC2] == 'f')
742 reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
743 reginfo2 [ins->sreg2].last_use = i;
744 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
745 /* The virtual register is allocated sequentially */
746 reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
747 reginfo2 [ins->sreg2 + 1].last_use = i;
748 if (reginfo2 [ins->sreg2 + 1].born_in == 0 || reginfo2 [ins->sreg2 + 1].born_in > i)
749 reginfo2 [ins->sreg2 + 1].born_in = i;
754 if (spec [MONO_INST_DEST]) {
757 if (dreg_is_fp (ins))
761 if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
762 reginfod [ins->dreg].killed_in = i;
763 reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
764 reginfod [ins->dreg].last_use = i;
765 if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
766 reginfod [ins->dreg].born_in = i;
768 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
770 reginfod [ins->dreg].preferred_mask = (regmask (dest_dreg));
772 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
773 /* The virtual register is allocated sequentially */
774 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
775 reginfod [ins->dreg + 1].last_use = i;
776 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
777 reginfod [ins->dreg + 1].born_in = i;
778 if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
779 reginfod [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
785 if (spec [MONO_INST_CLOB] == 'c') {
786 /* A call instruction implicitly uses all registers in call->out_ireg_args */
788 MonoCallInst *call = (MonoCallInst*)ins;
791 list = call->out_ireg_args;
797 regpair = (guint32)(gssize)(list->data);
798 hreg = regpair >> 24;
799 reg = regpair & 0xffffff;
801 reginfo [reg].prev_use = reginfo [reg].last_use;
802 reginfo [reg].last_use = i;
804 list = g_slist_next (list);
808 list = call->out_freg_args;
809 if (!use_fpstack && list) {
814 regpair = (guint32)(gssize)(list->data);
815 hreg = regpair >> 24;
816 reg = regpair & 0xffffff;
818 reginfof [reg].prev_use = reginfof [reg].last_use;
819 reginfof [reg].last_use = i;
821 list = g_slist_next (list);
826 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
831 // todo: check if we have anything left on fp stack, in verify mode?
834 DEBUG (print_regtrack (reginfo, rs->next_vireg));
835 DEBUG (print_regtrack (reginfof, rs->next_vfreg));
838 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
839 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
840 int dreg_high, sreg1_high;
841 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
842 const unsigned char *ip;
845 spec = ins_spec [ins->opcode];
853 dreg_mask = dreg_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
854 sreg1_mask = sreg1_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
855 sreg2_mask = sreg2_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
857 DEBUG (g_print ("processing:"));
858 DEBUG (print_ins (i, ins));
865 dest_sreg1 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC1]);
866 dest_sreg2 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC2]);
867 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
868 clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
869 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
874 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
875 if (dreg_is_fp (ins)) {
876 if (reginfof [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
879 spill_node = g_list_first (fspill_list);
880 g_assert (spill_node);
882 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
883 insert_before_ins (ins, tmp, store);
884 fspill_list = g_list_remove (fspill_list, spill_node->data);
889 if (spec [MONO_INST_SRC1] == 'f') {
890 if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
892 MonoInst *store = NULL;
894 if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
896 spill_node = g_list_first (fspill_list);
897 g_assert (spill_node);
899 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);
900 fspill_list = g_list_remove (fspill_list, spill_node->data);
904 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
905 load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
906 insert_before_ins (ins, tmp, load);
908 insert_before_ins (load, tmp, store);
912 if (spec [MONO_INST_SRC2] == 'f') {
913 if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
915 MonoInst *store = NULL;
917 if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
920 spill_node = g_list_first (fspill_list);
921 g_assert (spill_node);
922 if (spec [MONO_INST_SRC1] == 'f' && (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
923 spill_node = g_list_next (spill_node);
925 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
926 fspill_list = g_list_remove (fspill_list, spill_node->data);
930 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
931 load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
932 insert_before_ins (ins, tmp, load);
934 insert_before_ins (load, tmp, store);
942 if (dest_sreg2 != -1) {
943 if (rs->ifree_mask & (regmask (dest_sreg2))) {
944 if (is_global_ireg (ins->sreg2)) {
945 /* Argument already in hard reg, need to copy */
946 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
947 insert_before_ins (ins, tmp, copy);
950 DEBUG (g_print ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
951 assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
954 int need_spill = TRUE;
956 dreg_mask &= ~ (regmask (dest_sreg2));
957 sreg1_mask &= ~ (regmask (dest_sreg2));
960 * First check if dreg is assigned to dest_sreg2, since we
961 * can't spill a dreg.
963 val = rs->iassign [ins->dreg];
964 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
966 * the destination register is already assigned to
967 * dest_sreg2: we need to allocate another register for it
968 * and then copy from this to dest_sreg2.
971 new_dest = alloc_int_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg]);
972 g_assert (new_dest >= 0);
973 DEBUG (g_print ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
975 prev_dreg = ins->dreg;
976 assign_ireg (cfg, rs, ins->dreg, new_dest);
977 clob_dreg = ins->dreg;
978 create_copy_ins (cfg, dest_sreg2, new_dest, ins, ip, FALSE);
982 if (is_global_ireg (ins->sreg2)) {
983 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
984 insert_before_ins (ins, tmp, copy);
987 val = rs->iassign [ins->sreg2];
988 if (val == dest_sreg2) {
989 /* sreg2 is already assigned to the correct register */
992 else if ((val >= 0) || (val < -1)) {
993 /* FIXME: sreg2 already assigned to another register */
994 g_assert_not_reached ();
999 DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1000 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
1001 mono_regstate_free_int (rs, dest_sreg2);
1004 if (!is_global_ireg (ins->sreg2))
1005 /* force-set sreg2 */
1006 assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1008 ins->sreg2 = dest_sreg2;
1014 fp = dreg_is_fp (ins);
1015 if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
1016 prev_dreg = ins->dreg;
1018 if (spec [MONO_INST_DEST] == 'b') {
1020 * The dest reg is read by the instruction, not written, so
1021 * avoid allocating sreg1/sreg2 to the same reg.
1023 if (dest_sreg1 != -1)
1024 dreg_mask &= ~ (regmask (dest_sreg1));
1025 if (dest_sreg2 != -1)
1026 dreg_mask &= ~ (regmask (dest_sreg2));
1030 * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1031 * various complex situations.
1033 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1034 guint32 dreg2, dest_dreg2;
1036 g_assert (is_soft_reg (ins->dreg, fp));
1038 if (dest_dreg != -1) {
1039 if (rs->iassign [ins->dreg] != dest_dreg)
1040 free_up_ireg (cfg, tmp, ins, dest_dreg);
1042 dreg2 = ins->dreg + 1;
1043 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
1044 if (dest_dreg2 != -1) {
1045 if (rs->iassign [dreg2] != dest_dreg2)
1046 free_up_ireg (cfg, tmp, ins, dest_dreg2);
1051 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
1052 if (dest_dreg != -1)
1053 dreg_mask = (regmask (dest_dreg));
1055 val = rassign (cfg, ins->dreg, fp);
1060 /* the register gets spilled after this inst */
1063 val = alloc_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg], fp);
1064 assign_reg (cfg, rs, ins->dreg, val, fp);
1066 create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
1069 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
1073 /* Handle regpairs */
1074 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1075 int reg2 = prev_dreg + 1;
1078 g_assert (prev_dreg > -1);
1079 g_assert (!is_global_ireg (rs->iassign [prev_dreg]));
1080 mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->iassign [prev_dreg]);
1081 val = rs->iassign [reg2];
1085 /* the register gets spilled after this inst */
1088 val = mono_regstate_alloc_int (rs, mask);
1090 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1092 create_spilled_store (cfg, spill, val, reg2, ins, fp);
1095 if (! (mask & (regmask (val)))) {
1096 val = mono_regstate_alloc_int (rs, mask);
1098 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1100 /* Reallocate hreg to the correct register */
1101 create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
1103 mono_regstate_free_int (rs, rs->iassign [reg2]);
1107 DEBUG (g_print ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1108 assign_reg (cfg, rs, reg2, val, fp);
1113 if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1114 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1115 mono_regstate_free_int (rs, val);
1119 if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && (fp ? reginfof : reginfo) [prev_dreg].born_in >= i) {
1121 * In theory, we could free up the hreg even if the vreg is alive,
1122 * but branches inside bblocks force us to assign the same hreg
1123 * to a vreg every time it is encountered.
1125 int dreg = rassign (cfg, prev_dreg, fp);
1126 g_assert (dreg >= 0);
1127 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, (fp ? reginfof : reginfo) [prev_dreg].born_in));
1129 mono_regstate_free_float (rs, dreg);
1131 mono_regstate_free_int (rs, dreg);
1134 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1135 /* this instruction only outputs to dest_dreg, need to copy */
1136 create_copy_ins (cfg, ins->dreg, dest_dreg, ins, ip, fp);
1137 ins->dreg = dest_dreg;
1140 if (rs->fsymbolic [dest_dreg] >= MONO_MAX_FREGS)
1141 free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1144 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1145 free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1149 if (spec [MONO_INST_DEST] == 'b') {
1151 * The dest reg is read by the instruction, not written, so
1152 * avoid allocating sreg1/sreg2 to the same reg.
1154 sreg1_mask &= ~ (regmask (ins->dreg));
1155 sreg2_mask &= ~ (regmask (ins->dreg));
1161 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1162 DEBUG (g_print ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1163 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
1164 mono_regstate_free_int (rs, clob_reg);
1167 if (spec [MONO_INST_CLOB] == 'c') {
1168 int j, s, dreg, dreg2;
1171 clob_mask = MONO_ARCH_CALLEE_REGS;
1174 * Need to avoid spilling the dreg since the dreg is not really
1175 * clobbered by the call.
1177 if ((prev_dreg != -1) && !dreg_is_fp (ins))
1178 dreg = rassign (cfg, prev_dreg, dreg_is_fp (ins));
1182 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
1183 dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (ins));
1187 for (j = 0; j < MONO_MAX_IREGS; ++j) {
1189 if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
1190 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
1191 mono_regstate_free_int (rs, j);
1196 clob_mask = MONO_ARCH_CALLEE_FREGS;
1197 if ((prev_dreg != -1) && dreg_is_fp (ins))
1198 dreg = rassign (cfg, prev_dreg, dreg_is_fp (ins));
1202 for (j = 0; j < MONO_MAX_FREGS; ++j) {
1204 if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
1205 get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
1206 mono_regstate_free_float (rs, j);
1213 * TRACK ARGUMENT REGS
1215 if (spec [MONO_INST_CLOB] == 'c') {
1216 MonoCallInst *call = (MonoCallInst*)ins;
1220 * This needs to be done before assigning sreg1, so sreg1 will
1221 * not be assigned one of the argument regs.
1225 * Assign all registers in call->out_reg_args to the proper
1226 * argument registers.
1229 list = call->out_ireg_args;
1235 regpair = (guint32)(gssize)(list->data);
1236 hreg = regpair >> 24;
1237 reg = regpair & 0xffffff;
1239 assign_reg (cfg, rs, reg, hreg, FALSE);
1241 sreg1_mask &= ~(regmask (hreg));
1243 DEBUG (g_print ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1245 list = g_slist_next (list);
1247 g_slist_free (call->out_ireg_args);
1250 list = call->out_freg_args;
1251 if (list && !use_fpstack) {
1256 regpair = (guint32)(gssize)(list->data);
1257 hreg = regpair >> 24;
1258 reg = regpair & 0xffffff;
1260 assign_reg (cfg, rs, reg, hreg, TRUE);
1262 DEBUG (g_print ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
1264 list = g_slist_next (list);
1267 if (call->out_freg_args)
1268 g_slist_free (call->out_freg_args);
1274 fp = sreg1_is_fp (ins);
1275 if ((!fp || (fp && !use_fpstack))) {
1276 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
1277 g_assert (is_soft_reg (ins->sreg1, fp));
1279 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1280 if (dest_sreg1 != -1)
1281 g_assert (dest_sreg1 == ins->dreg);
1282 val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
1283 g_assert (val >= 0);
1284 assign_reg (cfg, rs, ins->sreg1, val, fp);
1286 DEBUG (g_print ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1288 g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
1289 val = mono_regstate_alloc_int (rs, regmask (dreg_high));
1290 g_assert (val >= 0);
1291 assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
1293 DEBUG (g_print ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
1295 /* Skip rest of this section */
1299 if (dest_sreg1 != -1) {
1300 sreg1_mask = regmask (dest_sreg1);
1302 if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
1303 DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1304 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
1305 mono_regstate_free_int (rs, dest_sreg1);
1307 if (is_global_ireg (ins->sreg1)) {
1308 /* The argument is already in a hard reg, need to copy */
1309 MonoInst *copy = create_copy_ins (cfg, dest_sreg1, ins->sreg1, NULL, ip, FALSE);
1310 insert_before_ins (ins, tmp, copy);
1311 ins->sreg1 = dest_sreg1;
1315 if (is_soft_reg (ins->sreg1, fp)) {
1316 val = rassign (cfg, ins->sreg1, fp);
1317 prev_sreg1 = ins->sreg1;
1321 /* the register gets spilled after this inst */
1325 if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (!is_global_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
1327 * Allocate the same hreg to sreg1 as well so the
1328 * peephole can get rid of the move.
1330 sreg1_mask = regmask (ins->dreg);
1333 val = alloc_reg (cfg, tmp, ins, sreg1_mask, ins->sreg1, ®info [ins->sreg1], fp);
1334 assign_reg (cfg, rs, ins->sreg1, val, fp);
1335 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1338 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
1340 * Need to insert before the instruction since it can
1343 insert_before_ins (ins, tmp, store);
1346 else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1347 g_assert_not_reached ();
1355 sreg2_mask &= ~(regmask (ins->sreg1));
1358 /* Handle the case when sreg1 is a regpair but dreg is not */
1359 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1]) && (spec [MONO_INST_CLOB] != '1')) {
1360 int reg2 = prev_sreg1 + 1;
1363 g_assert (prev_sreg1 > -1);
1364 g_assert (!is_global_ireg (rs->iassign [prev_sreg1]));
1365 mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->iassign [prev_sreg1]);
1366 val = rs->iassign [reg2];
1370 /* the register gets spilled after this inst */
1373 val = mono_regstate_alloc_int (rs, mask);
1375 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1377 g_assert_not_reached ();
1380 if (! (mask & (regmask (val)))) {
1381 /* The vreg is already allocated to a wrong hreg */
1383 g_assert_not_reached ();
1385 val = mono_regstate_alloc_int (rs, mask);
1387 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1389 /* Reallocate hreg to the correct register */
1390 create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
1392 mono_regstate_free_int (rs, rs->iassign [reg2]);
1398 DEBUG (g_print ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1399 assign_reg (cfg, rs, reg2, val, fp);
1402 /* Handle dreg==sreg1 */
1403 if (((dreg_is_fp (ins) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1404 MonoInst *sreg2_copy = NULL;
1406 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
1408 if (ins->dreg == ins->sreg2) {
1410 * copying sreg1 to dreg could clobber sreg2, so allocate a new
1413 int reg2 = alloc_reg (cfg, tmp, ins, dreg_mask, ins->sreg2, NULL, fp);
1415 DEBUG (g_print ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
1416 sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
1417 prev_sreg2 = ins->sreg2 = reg2;
1420 mono_regstate_free_float (rs, reg2);
1422 mono_regstate_free_int (rs, reg2);
1425 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
1426 /* Copying sreg1_high to dreg could also clobber sreg2 */
1427 if (rs->iassign [prev_sreg1 + 1] == ins->sreg2)
1429 g_assert_not_reached ();
1432 * sreg1 and dest are already allocated to the same regpair by the
1433 * SREG1 allocation code.
1435 g_assert (ins->sreg1 == ins->dreg);
1436 g_assert (dreg_high == sreg1_high);
1439 DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
1440 copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
1441 insert_before_ins (ins, tmp, copy);
1444 insert_before_ins (copy, tmp, sreg2_copy);
1447 * Need to prevent sreg2 to be allocated to sreg1, since that
1448 * would screw up the previous copy.
1450 sreg2_mask &= ~ (regmask (ins->sreg1));
1451 /* we set sreg1 to dest as well */
1452 prev_sreg1 = ins->sreg1 = ins->dreg;
1453 sreg2_mask &= ~ (regmask (ins->dreg));
1459 fp = sreg2_is_fp (ins);
1460 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
1461 g_assert_not_reached ();
1462 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
1463 val = rassign (cfg, ins->sreg2, fp);
1468 /* the register gets spilled after this inst */
1471 val = alloc_reg (cfg, tmp, ins, sreg2_mask, ins->sreg2, ®info [ins->sreg2], fp);
1472 assign_reg (cfg, rs, ins->sreg2, val, fp);
1473 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
1475 create_spilled_store (cfg, spill, val, prev_sreg2, ins, fp);
1483 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1484 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1485 mono_regstate_free_int (rs, ins->sreg1);
1487 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1488 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1489 mono_regstate_free_int (rs, ins->sreg2);
1492 DEBUG (print_ins (i, ins));
1493 /* this may result from a insert_before call */
1495 bb->code = tmp->data;
1501 g_list_free (fspill_list);