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) MINI_DEBUG(cfg->verbose_level, 2, 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 x86_desc [OP_LAST];
32 static const char*const * ins_spec = x86_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;
45 #elif defined(__alpha__)
46 const char * const alpha_desc [OP_LAST];
47 static const char*const * ins_spec = alpha_desc;
48 #elif defined(__ppc__) || defined(__powerpc__)
49 extern const char * const ppcg4 [OP_LAST];
50 static const char*const * ins_spec = ppcg4;
52 #error "Not implemented"
55 #define use_fpstack MONO_ARCH_USE_FPSTACK
58 g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
63 new_list = mono_mempool_alloc (mp, sizeof (GSList));
64 new_list->data = data;
65 new_list->next = NULL;
71 last->next = new_list;
79 * Duplicated here from regalloc.c so they can be inlined
80 * FIXME: Remove the old one after the new JIT is done
84 mono_regstate2_reset (MonoRegState *rs) {
85 rs->next_vireg = MONO_MAX_IREGS;
86 rs->next_vfreg = MONO_MAX_FREGS;
89 static inline MonoRegState*
90 mono_regstate2_new (void)
92 MonoRegState* rs = g_new0 (MonoRegState, 1);
94 mono_regstate2_reset (rs);
100 mono_regstate2_free (MonoRegState *rs) {
101 g_free (rs->iassign);
102 if (rs->iassign != rs->fassign)
103 g_free (rs->fassign);
108 mono_regstate2_assign (MonoRegState *rs) {
111 if (rs->next_vireg > rs->iassign_size) {
112 g_free (rs->iassign);
113 rs->iassign_size = MAX (rs->next_vireg, 256);
114 rs->iassign = g_malloc (rs->iassign_size * sizeof (int));
117 memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
118 memset (rs->iassign, -1, sizeof (rs->iassign [0]) * rs->next_vireg);
120 if (rs->next_vfreg > rs->fassign_size) {
121 g_free (rs->fassign);
122 rs->fassign = g_malloc (MAX (MONO_MAX_FREGS, rs->next_vfreg) * sizeof (int));
123 rs->fassign_size = rs->next_vfreg;
126 if (rs->next_vfreg > MONO_MAX_FREGS) {
127 memset (rs->fsymbolic, 0, MONO_MAX_IREGS * sizeof (rs->fsymbolic [0]));
128 memset (rs->fassign, -1, sizeof (rs->fassign [0]) * rs->next_vfreg);
133 mono_regstate2_alloc_int (MonoRegState *rs, regmask_t allow)
136 regmask_t mask = allow & rs->ifree_mask;
137 for (i = 0; i < MONO_MAX_IREGS; ++i) {
138 if (mask & ((regmask_t)1 << i)) {
139 rs->ifree_mask &= ~ ((regmask_t)1 << i);
140 rs->max_ireg = MAX (rs->max_ireg, i);
148 mono_regstate2_free_int (MonoRegState *rs, int reg)
151 rs->ifree_mask |= (regmask_t)1 << reg;
152 rs->isymbolic [reg] = 0;
157 mono_regstate2_alloc_float (MonoRegState *rs, regmask_t allow)
160 regmask_t mask = allow & rs->ffree_mask;
161 for (i = 0; i < MONO_MAX_FREGS; ++i) {
162 if (mask & ((regmask_t)1 << i)) {
163 rs->ffree_mask &= ~ ((regmask_t)1 << i);
171 mono_regstate2_free_float (MonoRegState *rs, int reg)
174 rs->ffree_mask |= (regmask_t)1 << reg;
175 rs->fsymbolic [reg] = 0;
180 mono_regstate2_next_long (MonoRegState *rs)
182 int rval = rs->next_vireg;
190 mono_regname_full (int reg, gboolean fp)
193 return mono_arch_fregname (reg);
195 return mono_arch_regname (reg);
199 mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, gboolean fp)
203 regpair = (((guint32)hreg) << 24) + vreg;
205 call->used_fregs |= 1 << hreg;
206 call->out_freg_args = g_slist_append_mempool (cfg->mempool, call->out_freg_args, (gpointer)(gssize)(regpair));
208 call->used_iregs |= 1 << hreg;
209 call->out_ireg_args = g_slist_append_mempool (cfg->mempool, call->out_ireg_args, (gpointer)(gssize)(regpair));
214 resize_spill_info (MonoCompile *cfg, gboolean fp)
216 MonoSpillInfo *orig_info = fp ? cfg->spill_info_float : cfg->spill_info;
217 int orig_len = fp ? cfg->spill_info_float_len : cfg->spill_info_len;
218 int new_len = orig_len ? orig_len * 2 : 16;
219 MonoSpillInfo *new_info;
222 new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
224 memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
225 for (i = orig_len; i < new_len; ++i)
226 new_info [i].offset = -1;
229 cfg->spill_info = new_info;
230 cfg->spill_info_len = new_len;
232 cfg->spill_info_float = new_info;
233 cfg->spill_info_float_len = new_len;
238 * returns the offset used by spillvar. It allocates a new
239 * spill variable if necessary.
242 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
246 if (G_UNLIKELY (spillvar >= cfg->spill_info_len)) {
247 resize_spill_info (cfg, FALSE);
248 g_assert (spillvar < cfg->spill_info_len);
251 info = &cfg->spill_info [spillvar];
252 if (info->offset == -1) {
253 cfg->stack_offset += sizeof (gpointer) - 1;
254 cfg->stack_offset &= ~(sizeof (gpointer) - 1);
256 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
257 info->offset = cfg->stack_offset;
258 cfg->stack_offset += sizeof (gpointer);
260 cfg->stack_offset += sizeof (gpointer);
261 info->offset = - cfg->stack_offset;
268 #if MONO_ARCH_USE_FPSTACK
271 * returns the offset used by spillvar. It allocates a new
272 * spill float variable if necessary.
273 * (same as mono_spillvar_offset but for float)
276 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
280 if (G_UNLIKELY (spillvar >= cfg->spill_info_float_len)) {
281 resize_spill_info (cfg, TRUE);
282 g_assert (spillvar < cfg->spill_info_float_len);
285 info = &cfg->spill_info_float [spillvar];
286 if (info->offset == -1) {
287 cfg->stack_offset += sizeof (double) - 1;
288 cfg->stack_offset &= ~(sizeof (double) - 1);
290 if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
291 info->offset = cfg->stack_offset;
292 cfg->stack_offset += sizeof (double);
294 cfg->stack_offset += sizeof (double);
295 info->offset = - cfg->stack_offset;
303 * Creates a store for spilled floating point items
306 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
309 MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
311 store->inst_destbasereg = cfg->frame_reg;
312 store->inst_offset = mono_spillvar_offset_float (cfg, spill);
314 DEBUG (printf ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
319 * Creates a load for spilled floating point items
322 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
325 MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
327 load->inst_basereg = cfg->frame_reg;
328 load->inst_offset = mono_spillvar_offset_float (cfg, spill);
330 DEBUG (printf ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
334 #endif /* MONO_ARCH_USE_FPSTACK */
336 #define regmask(reg) (((regmask_t)1) << (reg))
338 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
339 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
340 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
341 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
342 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
343 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
344 #define ireg_is_freeable(r) is_local_ireg ((r))
345 #define freg_is_freeable(r) is_hard_freg ((r))
347 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
348 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
349 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
350 #define rassign(cfg,reg,fp) ((fp) ? (cfg)->rs->fassign [(reg)] : (cfg)->rs->iassign [(reg)])
352 #define sreg1_is_fp(spec) (spec [MONO_INST_SRC1] == 'f')
353 #define sreg2_is_fp(spec) (spec [MONO_INST_SRC2] == 'f')
355 #ifdef MONO_ARCH_INST_IS_FLOAT
356 #define dreg_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
358 #define dreg_is_fp(spec) (spec [MONO_INST_DEST] == 'f')
361 #define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_spec [(ins)->opcode]))
362 #define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_spec [(ins)->opcode]))
363 #define dreg_is_fp_ins(ins) (dreg_is_fp (ins_spec [(ins)->opcode]))
365 #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)
367 #ifdef MONO_ARCH_IS_GLOBAL_IREG
368 #undef is_global_ireg
369 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
378 #if MONO_ARCH_USE_FPSTACK
379 int flags; /* used to track fp spill/load */
381 regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
384 #ifndef DISABLE_LOGGING
386 print_ins (int i, MonoInst *ins)
388 const char *spec = ins_spec [ins->opcode];
389 printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
391 g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
393 if (spec [MONO_INST_DEST]) {
394 gboolean fp = dreg_is_fp_ins (ins);
395 if (is_soft_reg (ins->dreg, fp)) {
396 if (spec [MONO_INST_DEST] == 'b') {
397 if (ins->inst_offset == 0)
398 printf (" [R%d] <-", ins->dreg);
400 printf (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
403 printf (" R%d <-", ins->dreg);
404 } else if (spec [MONO_INST_DEST] == 'b') {
405 if (ins->inst_offset == 0)
406 printf (" [%s] <-", mono_arch_regname (ins->dreg));
408 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
410 printf (" %s <-", mono_regname_full (ins->dreg, fp));
412 if (spec [MONO_INST_SRC1]) {
413 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
414 if (is_soft_reg (ins->sreg1, fp))
415 printf (" R%d", ins->sreg1);
416 else if (spec [MONO_INST_SRC1] == 'b')
417 printf (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
419 printf (" %s", mono_regname_full (ins->sreg1, fp));
421 if (spec [MONO_INST_SRC2]) {
422 gboolean fp = (spec [MONO_INST_SRC2] == 'f');
423 if (is_soft_reg (ins->sreg2, fp))
424 printf (" R%d", ins->sreg2);
426 printf (" %s", mono_regname_full (ins->sreg2, fp));
428 if (spec [MONO_INST_CLOB])
429 printf (" clobbers: %c", spec [MONO_INST_CLOB]);
434 print_regtrack (RegTrack *t, int num)
440 for (i = 0; i < num; ++i) {
443 if (i >= MONO_MAX_IREGS) {
444 g_snprintf (buf, sizeof(buf), "R%d", i);
447 r = mono_arch_regname (i);
448 printf ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].killed_in);
451 #endif /* DISABLE_LOGGING */
453 typedef struct InstList InstList;
461 static inline InstList*
462 inst_list_prepend (guint8 *mem, InstList *list, MonoInst *data)
464 InstList *item = (InstList*)mem;
474 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
479 * If this function is called multiple times, the new instructions are inserted
480 * in the proper order.
484 prev = item->next->data;
486 while (prev->next != ins)
488 to_insert->next = ins;
489 prev->next = to_insert;
491 to_insert->next = ins;
495 * insert_after_ins insert the new instruction before item->data, so
496 * we have to modify it to point to the first of the prepended instructions.
498 if (item->data == ins)
499 item->data = to_insert;
503 insert_after_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
506 while (ins->next != item->prev->data)
509 to_insert->next = ins->next;
510 ins->next = to_insert;
514 * Force the spilling of the variable in the symbolic register 'reg'.
517 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg, gboolean fp)
521 int *assign, *symbolic;
524 assign = cfg->rs->fassign;
525 symbolic = cfg->rs->fsymbolic;
528 assign = cfg->rs->iassign;
529 symbolic = cfg->rs->isymbolic;
533 /*i = cfg->rs->isymbolic [sel];
534 g_assert (i == reg);*/
536 spill = ++cfg->spill_count;
537 assign [i] = -spill - 1;
539 mono_regstate2_free_float (cfg->rs, sel);
541 mono_regstate2_free_int (cfg->rs, sel);
542 /* we need to create a spill var and insert a load to sel after the current instruction */
544 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
546 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
548 load->inst_basereg = cfg->frame_reg;
549 load->inst_offset = mono_spillvar_offset (cfg, spill);
550 insert_after_ins (ins, item, load);
551 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)));
553 i = mono_regstate2_alloc_float (cfg->rs, regmask (sel));
555 i = mono_regstate2_alloc_int (cfg->rs, regmask (sel));
561 /* This isn't defined on older glib versions and on some platforms */
562 #ifndef G_GUINT64_FORMAT
563 #define G_GUINT64_FORMAT "ul"
567 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_t regmask, int reg, gboolean fp)
571 int *assign, *symbolic;
574 assign = cfg->rs->fassign;
575 symbolic = cfg->rs->fsymbolic;
578 assign = cfg->rs->iassign;
579 symbolic = cfg->rs->isymbolic;
582 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));
583 /* exclude the registers in the current instruction */
584 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))) {
585 if (is_soft_reg (ins->sreg1, fp))
586 regmask &= ~ (regmask (rassign (cfg, ins->sreg1, fp)));
588 regmask &= ~ (regmask (ins->sreg1));
589 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
591 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))) {
592 if (is_soft_reg (ins->sreg2, fp))
593 regmask &= ~ (regmask (rassign (cfg, ins->sreg2, fp)));
595 regmask &= ~ (regmask (ins->sreg2));
596 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
598 if ((dreg_is_fp_ins (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
599 regmask &= ~ (regmask (ins->dreg));
600 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
603 DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
604 g_assert (regmask); /* need at least a register we can free */
606 /* we should track prev_use and spill the register that's farther */
608 for (i = 0; i < MONO_MAX_FREGS; ++i) {
609 if (regmask & (regmask (i))) {
611 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
616 i = cfg->rs->fsymbolic [sel];
617 spill = ++cfg->spill_count;
618 cfg->rs->fassign [i] = -spill - 1;
619 mono_regstate2_free_float (cfg->rs, sel);
622 for (i = 0; i < MONO_MAX_IREGS; ++i) {
623 if (regmask & (regmask (i))) {
625 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
630 i = cfg->rs->isymbolic [sel];
631 spill = ++cfg->spill_count;
632 cfg->rs->iassign [i] = -spill - 1;
633 mono_regstate2_free_int (cfg->rs, sel);
636 /* we need to create a spill var and insert a load to sel after the current instruction */
637 MONO_INST_NEW (cfg, load, fp ? OP_LOADR8_MEMBASE : OP_LOAD_MEMBASE);
639 load->inst_basereg = cfg->frame_reg;
640 load->inst_offset = mono_spillvar_offset (cfg, spill);
641 insert_after_ins (ins, item, load);
642 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)));
644 i = mono_regstate2_alloc_float (cfg->rs, regmask (sel));
646 i = mono_regstate2_alloc_int (cfg->rs, regmask (sel));
653 free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
655 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
656 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
657 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
658 mono_regstate2_free_int (cfg->rs, hreg);
663 free_up_reg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg, gboolean fp)
666 if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
667 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
668 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
669 mono_regstate2_free_float (cfg->rs, hreg);
673 if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
674 DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
675 get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
676 mono_regstate2_free_int (cfg->rs, hreg);
682 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins, const unsigned char *ip, gboolean fp)
687 MONO_INST_NEW (cfg, copy, OP_FMOVE);
689 MONO_INST_NEW (cfg, copy, OP_MOVE);
695 copy->next = ins->next;
696 copy->cil_code = ins->cil_code;
699 DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
704 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins, gboolean fp)
707 MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
709 store->inst_destbasereg = cfg->frame_reg;
710 store->inst_offset = mono_spillvar_offset (cfg, spill);
712 store->next = ins->next;
715 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)));
719 /* flags used in reginfo->flags */
721 MONO_FP_NEEDS_LOAD_SPILL = regmask (0),
722 MONO_FP_NEEDS_SPILL = regmask (1),
723 MONO_FP_NEEDS_LOAD = regmask (2)
727 alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
731 if (info && info->preferred_mask) {
732 val = mono_regstate2_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
734 DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
739 val = mono_regstate2_alloc_int (cfg->rs, dest_mask);
741 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
747 alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg)
751 val = mono_regstate2_alloc_float (cfg->rs, dest_mask);
754 val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
761 alloc_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
764 return alloc_float_reg (cfg, tmp, ins, dest_mask, sym_reg);
766 return alloc_int_reg (cfg, tmp, ins, dest_mask, sym_reg, info);
770 assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
773 g_assert (reg >= MONO_MAX_FREGS);
774 g_assert (hreg < MONO_MAX_FREGS);
775 g_assert (! is_global_freg (hreg));
777 rs->fassign [reg] = hreg;
778 rs->fsymbolic [hreg] = reg;
779 rs->ffree_mask &= ~ (regmask (hreg));
782 g_assert (reg >= MONO_MAX_IREGS);
783 g_assert (hreg < MONO_MAX_IREGS);
784 g_assert (! is_global_ireg (hreg));
786 rs->iassign [reg] = hreg;
787 rs->isymbolic [hreg] = reg;
788 rs->ifree_mask &= ~ (regmask (hreg));
793 assign_ireg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg)
795 assign_reg (cfg, rs, reg, hreg, FALSE);
799 * Local register allocation.
800 * We first scan the list of instructions and we save the liveness info of
801 * each register (when the register is first used, when it's value is set etc.).
802 * We also reverse the list of instructions (in the InstList list) because assigning
803 * registers backwards allows for more tricks to be used.
806 mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
809 MonoRegState *rs = cfg->rs;
810 int i, val, fpcount, ins_count;
811 RegTrack *reginfo, *reginfof;
812 RegTrack *reginfo1, *reginfo2, *reginfod;
813 InstList *tmp, *reversed = NULL;
815 GList *fspill_list = NULL;
818 guint8 *inst_list, *mem;
819 #if MONO_ARCH_USE_FPSTACK
820 gboolean need_fpstack = (use_fpstack && bb->max_freg > MONO_MAX_FREGS);
826 rs->next_vireg = bb->max_ireg;
827 rs->next_vfreg = bb->max_freg;
828 mono_regstate2_assign (rs);
830 rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
831 rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
834 rs->ffree_mask = 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE));
838 /*if (cfg->opt & MONO_OPT_COPYPROP)
839 local_copy_prop (cfg, ins);*/
841 if (cfg->reginfo && cfg->reginfo_len < rs->next_vireg) {
844 reginfo = cfg->reginfo;
846 cfg->reginfo_len = MAX (256, rs->next_vireg * 2);
847 reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
850 g_assert (cfg->reginfo_len >= rs->next_vireg);
852 if (cfg->reginfof && cfg->reginfof_len < rs->next_vfreg) {
853 cfg->reginfof = NULL;
855 reginfof = cfg->reginfof;
857 cfg->reginfof_len = MAX (256, rs->next_vfreg * 2);
858 reginfof = cfg->reginfof = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfof_len);
861 g_assert (cfg->reginfof_len >= rs->next_vfreg);
863 memset (reginfo, 0, rs->next_vireg * sizeof (RegTrack));
864 memset (reginfof, 0, rs->next_vfreg * sizeof (RegTrack));
867 for (ins = bb->code; ins; ins = ins->next) {
868 spec = ins_spec [ins->opcode];
873 if (cfg->reverse_inst_list && (cfg->reverse_inst_list_len < ins_count)) {
874 cfg->reverse_inst_list = NULL;
877 inst_list = cfg->reverse_inst_list;
879 cfg->reverse_inst_list_len = MAX (ins_count, 1024);
880 inst_list = cfg->reverse_inst_list = mono_mempool_alloc (cfg->mempool, cfg->reverse_inst_list_len * sizeof (InstList));
886 DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb->block_num));
887 /* forward pass on the instructions to collect register liveness info */
888 for (ins = bb->code; ins; ins = ins->next) {
889 spec = ins_spec [ins->opcode];
891 if (G_UNLIKELY (!spec)) {
892 g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
895 DEBUG (print_ins (i, ins));
900 #if MONO_ARCH_USE_FPSTACK
904 if (spec [MONO_INST_SRC1] == 'f') {
905 spill = g_list_first (fspill_list);
906 if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
907 reginfof [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
908 fspill_list = g_list_remove (fspill_list, spill->data);
913 if (spec [MONO_INST_SRC2] == 'f') {
914 spill = g_list_first (fspill_list);
916 reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
917 fspill_list = g_list_remove (fspill_list, spill->data);
918 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
920 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
921 reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
927 if (dreg_is_fp (spec)) {
928 if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
929 if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
930 reginfof [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
932 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
941 if (spec [MONO_INST_SRC1]) {
942 if (spec [MONO_INST_SRC1] == 'f')
946 //reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
947 //reginfo1 [ins->sreg1].last_use = i;
948 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
949 /* The virtual register is allocated sequentially */
950 //reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
951 //reginfo1 [ins->sreg1 + 1].last_use = i;
952 if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
953 reginfo1 [ins->sreg1 + 1].born_in = i;
958 if (spec [MONO_INST_SRC2]) {
959 if (spec [MONO_INST_SRC2] == 'f')
963 //reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
964 //reginfo2 [ins->sreg2].last_use = i;
965 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
966 /* The virtual register is allocated sequentially */
967 //reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
968 //reginfo2 [ins->sreg2 + 1].last_use = i;
969 if (reginfo2 [ins->sreg2 + 1].born_in == 0 || reginfo2 [ins->sreg2 + 1].born_in > i)
970 reginfo2 [ins->sreg2 + 1].born_in = i;
975 if (spec [MONO_INST_DEST]) {
978 if (dreg_is_fp (spec))
982 if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
983 reginfod [ins->dreg].killed_in = i;
984 //reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
985 //reginfod [ins->dreg].last_use = i;
986 if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
987 reginfod [ins->dreg].born_in = i;
989 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
991 reginfod [ins->dreg].preferred_mask = (regmask (dest_dreg));
993 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
994 /* The virtual register is allocated sequentially */
995 //reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
996 //reginfod [ins->dreg + 1].last_use = i;
997 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
998 reginfod [ins->dreg + 1].born_in = i;
999 if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
1000 reginfod [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
1006 if (spec [MONO_INST_CLOB] == 'c') {
1007 /* A call instruction implicitly uses all registers in call->out_ireg_args */
1009 MonoCallInst *call = (MonoCallInst*)ins;
1012 list = call->out_ireg_args;
1018 regpair = (guint32)(gssize)(list->data);
1019 hreg = regpair >> 24;
1020 reg = regpair & 0xffffff;
1022 //reginfo [reg].prev_use = reginfo [reg].last_use;
1023 //reginfo [reg].last_use = i;
1025 list = g_slist_next (list);
1029 list = call->out_freg_args;
1030 if (!use_fpstack && list) {
1035 regpair = (guint32)(gssize)(list->data);
1036 hreg = regpair >> 24;
1037 reg = regpair & 0xffffff;
1039 //reginfof [reg].prev_use = reginfof [reg].last_use;
1040 //reginfof [reg].last_use = i;
1042 list = g_slist_next (list);
1047 reversed = inst_list_prepend (mem, reversed, ins);
1048 mem += sizeof (InstList);
1052 // todo: check if we have anything left on fp stack, in verify mode?
1055 DEBUG (print_regtrack (reginfo, rs->next_vireg));
1056 DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1059 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
1060 int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
1061 int dreg_high, sreg1_high;
1062 regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
1063 regmask_t dreg_fixed_mask, sreg1_fixed_mask, sreg2_fixed_mask;
1064 const unsigned char *ip;
1067 spec = ins_spec [ins->opcode];
1075 dreg_mask = dreg_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1076 sreg1_mask = sreg1_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1077 sreg2_mask = sreg2_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
1079 DEBUG (printf ("processing:"));
1080 DEBUG (print_ins (i, ins));
1087 dest_sreg1 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC1]);
1088 dest_sreg2 = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_SRC2]);
1089 dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
1090 clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
1091 sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
1093 #ifdef MONO_ARCH_INST_FIXED_MASK
1094 sreg1_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC1]);
1095 sreg2_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC2]);
1096 dreg_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_DEST]);
1098 sreg1_fixed_mask = sreg2_fixed_mask = dreg_fixed_mask = 0;
1104 #if MONO_ARCH_USE_FPSTACK
1105 if (need_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
1106 if (dreg_is_fp (spec)) {
1107 if (reginfof [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
1110 spill_node = g_list_first (fspill_list);
1111 g_assert (spill_node);
1113 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
1114 insert_before_ins (ins, tmp, store);
1115 fspill_list = g_list_remove (fspill_list, spill_node->data);
1120 if (spec [MONO_INST_SRC1] == 'f') {
1121 if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
1123 MonoInst *store = NULL;
1125 if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1127 spill_node = g_list_first (fspill_list);
1128 g_assert (spill_node);
1130 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);
1131 fspill_list = g_list_remove (fspill_list, spill_node->data);
1135 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1136 load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
1137 insert_before_ins (ins, tmp, load);
1139 insert_before_ins (load, tmp, store);
1143 if (spec [MONO_INST_SRC2] == 'f') {
1144 if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
1146 MonoInst *store = NULL;
1148 if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
1151 spill_node = g_list_first (fspill_list);
1152 g_assert (spill_node);
1153 if (spec [MONO_INST_SRC1] == 'f' && (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
1154 spill_node = g_list_next (spill_node);
1156 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
1157 fspill_list = g_list_remove (fspill_list, spill_node->data);
1161 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1162 load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
1163 insert_before_ins (ins, tmp, load);
1165 insert_before_ins (load, tmp, store);
1174 if (dest_sreg2 != -1) {
1175 if (rs->ifree_mask & (regmask (dest_sreg2))) {
1176 if (is_global_ireg (ins->sreg2)) {
1177 /* Argument already in hard reg, need to copy */
1178 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1179 insert_before_ins (ins, tmp, copy);
1182 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
1183 assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1186 int need_spill = TRUE;
1188 dreg_mask &= ~ (regmask (dest_sreg2));
1189 sreg1_mask &= ~ (regmask (dest_sreg2));
1192 * First check if dreg is assigned to dest_sreg2, since we
1193 * can't spill a dreg.
1195 val = rs->iassign [ins->dreg];
1196 if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
1198 * the destination register is already assigned to
1199 * dest_sreg2: we need to allocate another register for it
1200 * and then copy from this to dest_sreg2.
1203 new_dest = alloc_int_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg]);
1204 g_assert (new_dest >= 0);
1205 DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
1207 prev_dreg = ins->dreg;
1208 assign_ireg (cfg, rs, ins->dreg, new_dest);
1209 clob_dreg = ins->dreg;
1210 create_copy_ins (cfg, dest_sreg2, new_dest, ins, ip, FALSE);
1211 mono_regstate_free_int (rs, dest_sreg2);
1215 if (is_global_ireg (ins->sreg2)) {
1216 MonoInst *copy = create_copy_ins (cfg, dest_sreg2, ins->sreg2, NULL, ip, FALSE);
1217 insert_before_ins (ins, tmp, copy);
1220 val = rs->iassign [ins->sreg2];
1221 if (val == dest_sreg2) {
1222 /* sreg2 is already assigned to the correct register */
1225 else if ((val >= 0) || (val < -1)) {
1226 /* FIXME: sreg2 already assigned to another register */
1227 g_assert_not_reached ();
1232 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
1233 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
1234 mono_regstate2_free_int (rs, dest_sreg2);
1237 if (!is_global_ireg (ins->sreg2))
1238 /* force-set sreg2 */
1239 assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
1241 ins->sreg2 = dest_sreg2;
1247 fp = dreg_is_fp (spec);
1248 if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
1249 prev_dreg = ins->dreg;
1251 if (spec [MONO_INST_DEST] == 'b') {
1253 * The dest reg is read by the instruction, not written, so
1254 * avoid allocating sreg1/sreg2 to the same reg.
1256 if (dest_sreg1 != -1)
1257 dreg_mask &= ~ (regmask (dest_sreg1));
1258 if (dest_sreg2 != -1)
1259 dreg_mask &= ~ (regmask (dest_sreg2));
1261 val = rassign (cfg, ins->dreg, fp);
1262 if (is_soft_reg (ins->dreg, fp) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
1263 /* DREG is already allocated to a register needed for sreg1 */
1264 get_register_force_spilling (cfg, tmp, ins, ins->dreg, FALSE);
1265 mono_regstate2_free_int (rs, val);
1270 * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1271 * various complex situations.
1273 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1274 guint32 dreg2, dest_dreg2;
1276 g_assert (is_soft_reg (ins->dreg, fp));
1278 if (dest_dreg != -1) {
1279 if (rs->iassign [ins->dreg] != dest_dreg)
1280 free_up_ireg (cfg, tmp, ins, dest_dreg);
1282 dreg2 = ins->dreg + 1;
1283 dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
1284 if (dest_dreg2 != -1) {
1285 if (rs->iassign [dreg2] != dest_dreg2)
1286 free_up_ireg (cfg, tmp, ins, dest_dreg2);
1291 if (dreg_fixed_mask) {
1293 if (is_global_ireg (ins->dreg)) {
1295 * The argument is already in a hard reg, but that reg is
1296 * not usable by this instruction, so allocate a new one.
1298 val = mono_regstate2_alloc_int (rs, dreg_fixed_mask);
1300 val = get_register_spilling (cfg, tmp, ins, dreg_fixed_mask, -1, fp);
1301 mono_regstate2_free_int (rs, val);
1307 dreg_mask &= dreg_fixed_mask;
1310 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
1311 if (dest_dreg != -1)
1312 dreg_mask = (regmask (dest_dreg));
1314 val = rassign (cfg, ins->dreg, fp);
1319 /* the register gets spilled after this inst */
1322 val = alloc_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg], fp);
1323 assign_reg (cfg, rs, ins->dreg, val, fp);
1325 create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
1328 DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
1332 /* Handle regpairs */
1333 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
1334 int reg2 = prev_dreg + 1;
1337 g_assert (prev_dreg > -1);
1338 g_assert (!is_global_ireg (rs->iassign [prev_dreg]));
1339 mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->iassign [prev_dreg]);
1340 val = rs->iassign [reg2];
1344 /* the register gets spilled after this inst */
1347 val = mono_regstate2_alloc_int (rs, mask);
1349 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1351 create_spilled_store (cfg, spill, val, reg2, ins, fp);
1354 if (! (mask & (regmask (val)))) {
1355 val = mono_regstate2_alloc_int (rs, mask);
1357 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1359 /* Reallocate hreg to the correct register */
1360 create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
1362 mono_regstate2_free_int (rs, rs->iassign [reg2]);
1366 DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
1367 assign_reg (cfg, rs, reg2, val, fp);
1370 ins->backend.reg3 = val;
1372 if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
1373 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
1374 mono_regstate2_free_int (rs, val);
1378 if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && (fp ? reginfof : reginfo) [prev_dreg].born_in >= i) {
1380 * In theory, we could free up the hreg even if the vreg is alive,
1381 * but branches inside bblocks force us to assign the same hreg
1382 * to a vreg every time it is encountered.
1384 int dreg = rassign (cfg, prev_dreg, fp);
1385 g_assert (dreg >= 0);
1386 DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, (fp ? reginfof : reginfo) [prev_dreg].born_in));
1388 mono_regstate2_free_float (rs, dreg);
1390 mono_regstate2_free_int (rs, dreg);
1393 if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
1394 /* this instruction only outputs to dest_dreg, need to copy */
1395 create_copy_ins (cfg, ins->dreg, dest_dreg, ins, ip, fp);
1396 ins->dreg = dest_dreg;
1399 if (rs->fsymbolic [dest_dreg] >= MONO_MAX_FREGS)
1400 free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1403 if (rs->isymbolic [dest_dreg] >= MONO_MAX_IREGS)
1404 free_up_reg (cfg, tmp, ins, dest_dreg, fp);
1408 if (spec [MONO_INST_DEST] == 'b') {
1410 * The dest reg is read by the instruction, not written, so
1411 * avoid allocating sreg1/sreg2 to the same reg.
1413 sreg1_mask &= ~ (regmask (ins->dreg));
1414 sreg2_mask &= ~ (regmask (ins->dreg));
1420 if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
1421 DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1422 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
1423 mono_regstate2_free_int (rs, clob_reg);
1426 if (spec [MONO_INST_CLOB] == 'c') {
1427 int j, s, dreg, dreg2;
1430 clob_mask = MONO_ARCH_CALLEE_REGS;
1433 * Need to avoid spilling the dreg since the dreg is not really
1434 * clobbered by the call.
1436 if ((prev_dreg != -1) && !dreg_is_fp (spec))
1437 dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
1441 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
1442 dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (spec));
1446 for (j = 0; j < MONO_MAX_IREGS; ++j) {
1448 if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
1449 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
1450 mono_regstate2_free_int (rs, j);
1455 clob_mask = MONO_ARCH_CALLEE_FREGS;
1456 if ((prev_dreg != -1) && dreg_is_fp (spec))
1457 dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
1461 for (j = 0; j < MONO_MAX_FREGS; ++j) {
1463 if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
1464 get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
1465 mono_regstate2_free_float (rs, j);
1472 * TRACK ARGUMENT REGS
1474 if (spec [MONO_INST_CLOB] == 'c') {
1475 MonoCallInst *call = (MonoCallInst*)ins;
1479 * This needs to be done before assigning sreg1, so sreg1 will
1480 * not be assigned one of the argument regs.
1484 * Assign all registers in call->out_reg_args to the proper
1485 * argument registers.
1488 list = call->out_ireg_args;
1494 regpair = (guint32)(gssize)(list->data);
1495 hreg = regpair >> 24;
1496 reg = regpair & 0xffffff;
1498 assign_reg (cfg, rs, reg, hreg, FALSE);
1500 sreg1_mask &= ~(regmask (hreg));
1502 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
1504 list = g_slist_next (list);
1508 list = call->out_freg_args;
1509 if (list && !use_fpstack) {
1514 regpair = (guint32)(gssize)(list->data);
1515 hreg = regpair >> 24;
1516 reg = regpair & 0xffffff;
1518 assign_reg (cfg, rs, reg, hreg, TRUE);
1520 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
1522 list = g_slist_next (list);
1530 fp = sreg1_is_fp (spec);
1531 if ((!fp || (fp && !use_fpstack))) {
1532 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
1533 g_assert (is_soft_reg (ins->sreg1, fp));
1535 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1536 if (dest_sreg1 != -1)
1537 g_assert (dest_sreg1 == ins->dreg);
1538 val = mono_regstate2_alloc_int (rs, regmask (ins->dreg));
1539 g_assert (val >= 0);
1540 assign_reg (cfg, rs, ins->sreg1, val, fp);
1542 DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1544 g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
1545 val = mono_regstate2_alloc_int (rs, regmask (dreg_high));
1546 g_assert (val >= 0);
1547 assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
1549 DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
1551 /* Skip rest of this section */
1555 if (sreg1_fixed_mask) {
1557 if (is_global_ireg (ins->sreg1)) {
1559 * The argument is already in a hard reg, but that reg is
1560 * not usable by this instruction, so allocate a new one.
1562 val = mono_regstate2_alloc_int (rs, sreg1_fixed_mask);
1564 val = get_register_spilling (cfg, tmp, ins, sreg1_fixed_mask, -1, fp);
1565 mono_regstate2_free_int (rs, val);
1568 /* Fall through to the dest_sreg1 != -1 case */
1571 sreg1_mask &= sreg1_fixed_mask;
1574 if (dest_sreg1 != -1) {
1575 sreg1_mask = regmask (dest_sreg1);
1577 if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
1578 DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
1579 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
1580 mono_regstate2_free_int (rs, dest_sreg1);
1582 if (is_global_ireg (ins->sreg1)) {
1583 /* The argument is already in a hard reg, need to copy */
1584 MonoInst *copy = create_copy_ins (cfg, dest_sreg1, ins->sreg1, NULL, ip, FALSE);
1585 insert_before_ins (ins, tmp, copy);
1586 ins->sreg1 = dest_sreg1;
1590 if (is_soft_reg (ins->sreg1, fp)) {
1591 val = rassign (cfg, ins->sreg1, fp);
1592 prev_sreg1 = ins->sreg1;
1596 /* the register gets spilled after this inst */
1600 if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
1602 * Allocate the same hreg to sreg1 as well so the
1603 * peephole can get rid of the move.
1605 sreg1_mask = regmask (ins->dreg);
1608 val = alloc_reg (cfg, tmp, ins, sreg1_mask, ins->sreg1, ®info [ins->sreg1], fp);
1609 assign_reg (cfg, rs, ins->sreg1, val, fp);
1610 DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
1613 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
1615 * Need to insert before the instruction since it can
1618 insert_before_ins (ins, tmp, store);
1621 else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
1622 create_copy_ins (cfg, dest_sreg1, val, ins, ip, fp);
1630 sreg2_mask &= ~(regmask (ins->sreg1));
1633 /* Handle the case when sreg1 is a regpair but dreg is not */
1634 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1]) && (spec [MONO_INST_CLOB] != '1')) {
1635 int reg2 = prev_sreg1 + 1;
1638 g_assert (prev_sreg1 > -1);
1639 g_assert (!is_global_ireg (rs->iassign [prev_sreg1]));
1640 mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->iassign [prev_sreg1]);
1641 val = rs->iassign [reg2];
1645 /* the register gets spilled after this inst */
1648 val = mono_regstate2_alloc_int (rs, mask);
1650 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1652 g_assert_not_reached ();
1655 if (! (mask & (regmask (val)))) {
1656 /* The vreg is already allocated to a wrong hreg */
1658 g_assert_not_reached ();
1660 val = mono_regstate2_alloc_int (rs, mask);
1662 val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
1664 /* Reallocate hreg to the correct register */
1665 create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
1667 mono_regstate2_free_int (rs, rs->iassign [reg2]);
1673 DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
1674 assign_reg (cfg, rs, reg2, val, fp);
1677 /* Handle dreg==sreg1 */
1678 if (((dreg_is_fp (spec) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
1679 MonoInst *sreg2_copy = NULL;
1681 gboolean fp = (spec [MONO_INST_SRC1] == 'f');
1683 if (ins->dreg == ins->sreg2) {
1685 * copying sreg1 to dreg could clobber sreg2, so allocate a new
1688 int reg2 = alloc_reg (cfg, tmp, ins, dreg_mask, ins->sreg2, NULL, fp);
1690 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
1691 sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
1692 prev_sreg2 = ins->sreg2 = reg2;
1695 mono_regstate2_free_float (rs, reg2);
1697 mono_regstate2_free_int (rs, reg2);
1700 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
1701 /* Copying sreg1_high to dreg could also clobber sreg2 */
1702 if (rs->iassign [prev_sreg1 + 1] == ins->sreg2)
1704 g_assert_not_reached ();
1707 * sreg1 and dest are already allocated to the same regpair by the
1708 * SREG1 allocation code.
1710 g_assert (ins->sreg1 == ins->dreg);
1711 g_assert (dreg_high == sreg1_high);
1714 DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
1715 copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
1716 insert_before_ins (ins, tmp, copy);
1719 insert_before_ins (copy, tmp, sreg2_copy);
1722 * Need to prevent sreg2 to be allocated to sreg1, since that
1723 * would screw up the previous copy.
1725 sreg2_mask &= ~ (regmask (ins->sreg1));
1726 /* we set sreg1 to dest as well */
1727 prev_sreg1 = ins->sreg1 = ins->dreg;
1728 sreg2_mask &= ~ (regmask (ins->dreg));
1734 fp = sreg2_is_fp (spec);
1735 if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
1736 g_assert_not_reached ();
1737 if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
1738 val = rassign (cfg, ins->sreg2, fp);
1743 /* the register gets spilled after this inst */
1746 val = alloc_reg (cfg, tmp, ins, sreg2_mask, ins->sreg2, ®info [ins->sreg2], fp);
1747 assign_reg (cfg, rs, ins->sreg2, val, fp);
1748 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
1750 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg2, NULL, fp);
1752 * Need to insert before the instruction since it can
1755 insert_before_ins (ins, tmp, store);
1764 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1765 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1766 mono_regstate2_free_int (rs, ins->sreg1);
1768 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1769 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1770 mono_regstate2_free_int (rs, ins->sreg2);
1773 DEBUG (print_ins (i, ins));
1774 /* this may result from a insert_before call */
1776 bb->code = tmp->data;
1780 g_list_free (fspill_list);