#include "inssel.h"
#include "mini-arch.h"
-#define DEBUG(a) if (cfg->verbose_level > 1) a
+#define DEBUG(a) MINI_DEBUG(cfg->verbose_level, 2, a;)
#if defined(__x86_64__)
const char * const amd64_desc [OP_LAST];
const char * const sparc_desc [OP_LAST];
static const char*const * ins_spec = sparc_desc;
#elif defined(__i386__)
-#ifdef _MSC_VER
extern const char * const pentium_desc [OP_LAST];
-#else
-const char * const pentium_desc [OP_LAST];
-#endif
static const char*const * ins_spec = pentium_desc;
#elif defined(__ia64__)
const char * const ia64_desc [OP_LAST];
#elif defined(__arm__)
const char * const arm_cpu_desc [OP_LAST];
static const char*const * ins_spec = arm_cpu_desc;
+#elif defined(__s390x__)
+const char * const s390x_cpu_desc [OP_LAST];
+static const char*const * ins_spec = s390x_cpu_desc;
+#elif defined(__s390__)
+const char * const s390_cpu_desc [OP_LAST];
+static const char*const * ins_spec = s390_cpu_desc;
#else
#error "Not implemented"
#endif
#define use_fpstack MONO_ARCH_USE_FPSTACK
+static inline GSList*
+g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
+{
+ GSList *new_list;
+ GSList *last;
+
+ new_list = mono_mempool_alloc (mp, sizeof (GSList));
+ new_list->data = data;
+ new_list->next = NULL;
+
+ if (list) {
+ last = list;
+ while (last->next)
+ last = last->next;
+ last->next = new_list;
+
+ return list;
+ }
+ else
+ return new_list;
+}
+
+/**
+ * Duplicated here from regalloc.c so they can be inlined
+ * FIXME: Remove the old one after the new JIT is done
+ */
+
+static inline void
+mono_regstate2_reset (MonoRegState *rs) {
+ rs->next_vireg = MONO_MAX_IREGS;
+ rs->next_vfreg = MONO_MAX_FREGS;
+}
+
+static inline MonoRegState*
+mono_regstate2_new (void)
+{
+ MonoRegState* rs = g_new0 (MonoRegState, 1);
+
+ mono_regstate2_reset (rs);
+
+ return rs;
+}
+
+static inline void
+mono_regstate2_free (MonoRegState *rs) {
+ g_free (rs->iassign);
+ if (rs->iassign != rs->fassign)
+ g_free (rs->fassign);
+ g_free (rs);
+}
+
+static inline void
+mono_regstate2_assign (MonoRegState *rs) {
+ rs->max_ireg = -1;
+
+ if (rs->next_vireg > rs->iassign_size) {
+ g_free (rs->iassign);
+ rs->iassign_size = MAX (rs->next_vireg, 256);
+ rs->iassign = g_malloc (rs->iassign_size * sizeof (int));
+ }
+
+ memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
+ memset (rs->iassign, -1, sizeof (rs->iassign [0]) * rs->next_vireg);
+
+ if (rs->next_vfreg > rs->fassign_size) {
+ g_free (rs->fassign);
+ rs->fassign = g_malloc (MAX (MONO_MAX_FREGS, rs->next_vfreg) * sizeof (int));
+ rs->fassign_size = rs->next_vfreg;
+ }
+
+ if (rs->next_vfreg > MONO_MAX_FREGS) {
+ memset (rs->fsymbolic, 0, MONO_MAX_IREGS * sizeof (rs->fsymbolic [0]));
+ memset (rs->fassign, -1, sizeof (rs->fassign [0]) * rs->next_vfreg);
+ }
+}
+
+static inline int
+mono_regstate2_alloc_int (MonoRegState *rs, regmask_t allow)
+{
+ int i;
+ regmask_t mask = allow & rs->ifree_mask;
+ for (i = 0; i < MONO_MAX_IREGS; ++i) {
+ if (mask & ((regmask_t)1 << i)) {
+ rs->ifree_mask &= ~ ((regmask_t)1 << i);
+ rs->max_ireg = MAX (rs->max_ireg, i);
+ return i;
+ }
+ }
+ return -1;
+}
+
+static inline void
+mono_regstate2_free_int (MonoRegState *rs, int reg)
+{
+ if (reg >= 0) {
+ rs->ifree_mask |= (regmask_t)1 << reg;
+ rs->isymbolic [reg] = 0;
+ }
+}
+
+static inline int
+mono_regstate2_alloc_float (MonoRegState *rs, regmask_t allow)
+{
+ int i;
+ regmask_t mask = allow & rs->ffree_mask;
+ for (i = 0; i < MONO_MAX_FREGS; ++i) {
+ if (mask & ((regmask_t)1 << i)) {
+ rs->ffree_mask &= ~ ((regmask_t)1 << i);
+ return i;
+ }
+ }
+ return -1;
+}
+
+static inline void
+mono_regstate2_free_float (MonoRegState *rs, int reg)
+{
+ if (reg >= 0) {
+ rs->ffree_mask |= (regmask_t)1 << reg;
+ rs->fsymbolic [reg] = 0;
+ }
+}
+
+static inline int
+mono_regstate2_next_long (MonoRegState *rs)
+{
+ int rval = rs->next_vireg;
+
+ rs->next_vireg += 2;
+
+ return rval;
+}
+
const char*
mono_regname_full (int reg, gboolean fp)
{
}
void
-mono_call_inst_add_outarg_reg (MonoCallInst *call, int vreg, int hreg, gboolean fp)
+mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, gboolean fp)
{
guint32 regpair;
regpair = (((guint32)hreg) << 24) + vreg;
- if (fp)
- call->out_freg_args = g_slist_append (call->out_freg_args, (gpointer)(gssize)(regpair));
- else
- call->out_ireg_args = g_slist_append (call->out_ireg_args, (gpointer)(gssize)(regpair));
+ if (fp) {
+ call->used_fregs |= 1 << hreg;
+ call->out_freg_args = g_slist_append_mempool (cfg->mempool, call->out_freg_args, (gpointer)(gssize)(regpair));
+ } else {
+ call->used_iregs |= 1 << hreg;
+ call->out_ireg_args = g_slist_append_mempool (cfg->mempool, call->out_ireg_args, (gpointer)(gssize)(regpair));
+ }
+}
+
+static void
+resize_spill_info (MonoCompile *cfg, gboolean fp)
+{
+ MonoSpillInfo *orig_info = fp ? cfg->spill_info_float : cfg->spill_info;
+ int orig_len = fp ? cfg->spill_info_float_len : cfg->spill_info_len;
+ int new_len = orig_len ? orig_len * 2 : 16;
+ MonoSpillInfo *new_info;
+ int i;
+
+ new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
+ if (orig_info)
+ memcpy (new_info, orig_info, sizeof (MonoSpillInfo) * orig_len);
+ for (i = orig_len; i < new_len; ++i)
+ new_info [i].offset = -1;
+
+ if (!fp) {
+ cfg->spill_info = new_info;
+ cfg->spill_info_len = new_len;
+ } else {
+ cfg->spill_info_float = new_info;
+ cfg->spill_info_float_len = new_len;
+ }
}
/*
* returns the offset used by spillvar. It allocates a new
* spill variable if necessary.
*/
-static int
+static inline int
mono_spillvar_offset (MonoCompile *cfg, int spillvar)
{
- MonoSpillInfo **si, *info;
- int i = 0;
+ MonoSpillInfo *info;
- si = &cfg->spill_info;
-
- while (i <= spillvar) {
-
- if (!*si) {
- *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
- info->next = NULL;
- if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
- info->offset = cfg->stack_offset;
- cfg->stack_offset += sizeof (gpointer);
- } else {
- cfg->stack_offset += sizeof (gpointer);
- info->offset = - cfg->stack_offset;
- }
- }
+ if (G_UNLIKELY (spillvar >= cfg->spill_info_len)) {
+ resize_spill_info (cfg, FALSE);
+ g_assert (spillvar < cfg->spill_info_len);
+ }
- if (i == spillvar)
- return (*si)->offset;
+ info = &cfg->spill_info [spillvar];
+ if (info->offset == -1) {
+ cfg->stack_offset += sizeof (gpointer) - 1;
+ cfg->stack_offset &= ~(sizeof (gpointer) - 1);
- i++;
- si = &(*si)->next;
+ if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
+ info->offset = cfg->stack_offset;
+ cfg->stack_offset += sizeof (gpointer);
+ } else {
+ cfg->stack_offset += sizeof (gpointer);
+ info->offset = - cfg->stack_offset;
+ }
}
- g_assert_not_reached ();
- return 0;
+ return info->offset;
}
+#if MONO_ARCH_USE_FPSTACK
+
/*
* returns the offset used by spillvar. It allocates a new
* spill float variable if necessary.
* (same as mono_spillvar_offset but for float)
*/
-static int
+static inline int
mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
{
- MonoSpillInfo **si, *info;
- int i = 0;
+ MonoSpillInfo *info;
- si = &cfg->spill_info_float;
-
- while (i <= spillvar) {
-
- if (!*si) {
- *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
- info->next = NULL;
- if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
- cfg->stack_offset += 7;
- cfg->stack_offset &= ~7;
- info->offset = cfg->stack_offset;
- cfg->stack_offset += sizeof (double);
- } else {
- /* FIXME: align */
- cfg->stack_offset += sizeof (double);
- info->offset = - cfg->stack_offset;
- }
- }
+ if (G_UNLIKELY (spillvar >= cfg->spill_info_float_len)) {
+ resize_spill_info (cfg, TRUE);
+ g_assert (spillvar < cfg->spill_info_float_len);
+ }
- if (i == spillvar)
- return (*si)->offset;
+ info = &cfg->spill_info_float [spillvar];
+ if (info->offset == -1) {
+ cfg->stack_offset += sizeof (double) - 1;
+ cfg->stack_offset &= ~(sizeof (double) - 1);
- i++;
- si = &(*si)->next;
+ if (cfg->flags & MONO_CFG_HAS_SPILLUP) {
+ info->offset = cfg->stack_offset;
+ cfg->stack_offset += sizeof (double);
+ } else {
+ cfg->stack_offset += sizeof (double);
+ info->offset = - cfg->stack_offset;
+ }
}
- g_assert_not_reached ();
- return 0;
+ return info->offset;
}
/*
store->inst_destbasereg = cfg->frame_reg;
store->inst_offset = mono_spillvar_offset_float (cfg, spill);
- DEBUG (g_print ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
+ DEBUG (printf ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)store->inst_offset, reg));
return store;
}
load->inst_basereg = cfg->frame_reg;
load->inst_offset = mono_spillvar_offset_float (cfg, spill);
- DEBUG (g_print ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
+ DEBUG (printf ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill, (long)load->inst_offset, reg));
return load;
}
+#endif /* MONO_ARCH_USE_FPSTACK */
+
#define regmask(reg) (((regmask_t)1) << (reg))
#define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
#define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
#define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
#define rassign(cfg,reg,fp) ((fp) ? (cfg)->rs->fassign [(reg)] : (cfg)->rs->iassign [(reg)])
-#define sreg1_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_SRC1] == 'f')
-#define sreg2_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_SRC2] == 'f')
+
+#define sreg1_is_fp(spec) (spec [MONO_INST_SRC1] == 'f')
+#define sreg2_is_fp(spec) (spec [MONO_INST_SRC2] == 'f')
#ifdef MONO_ARCH_INST_IS_FLOAT
-#define dreg_is_fp(ins) (MONO_ARCH_INST_IS_FLOAT (ins_spec [(ins)->opcode] [MONO_INST_DEST]))
+#define dreg_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
#else
-#define dreg_is_fp(ins) (ins_spec [(ins)->opcode] [MONO_INST_DEST] == 'f')
+#define dreg_is_fp(spec) (spec [MONO_INST_DEST] == 'f')
#endif
+#define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_spec [(ins)->opcode]))
+#define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_spec [(ins)->opcode]))
+#define dreg_is_fp_ins(ins) (dreg_is_fp (ins_spec [(ins)->opcode]))
+
#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)
#ifdef MONO_ARCH_IS_GLOBAL_IREG
typedef struct {
int born_in;
int killed_in;
- int last_use;
- int prev_use;
+ /* Not (yet) used */
+ //int last_use;
+ //int prev_use;
+#if MONO_ARCH_USE_FPSTACK
int flags; /* used to track fp spill/load */
+#endif
regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */
} RegTrack;
+#ifndef DISABLE_LOGGING
static void
print_ins (int i, MonoInst *ins)
{
const char *spec = ins_spec [ins->opcode];
- g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
+ printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
if (!spec)
g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
if (spec [MONO_INST_DEST]) {
- gboolean fp = dreg_is_fp (ins);
+ gboolean fp = dreg_is_fp_ins (ins);
if (is_soft_reg (ins->dreg, fp)) {
if (spec [MONO_INST_DEST] == 'b') {
if (ins->inst_offset == 0)
- g_print (" [R%d] <-", ins->dreg);
+ printf (" [R%d] <-", ins->dreg);
else
- g_print (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
+ printf (" [R%d + 0x%lx] <-", ins->dreg, (long)ins->inst_offset);
}
else
- g_print (" R%d <-", ins->dreg);
+ printf (" R%d <-", ins->dreg);
} else if (spec [MONO_INST_DEST] == 'b') {
if (ins->inst_offset == 0)
- g_print (" [%s] <-", mono_arch_regname (ins->dreg));
+ printf (" [%s] <-", mono_arch_regname (ins->dreg));
else
- g_print (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
+ printf (" [%s + 0x%lx] <-", mono_arch_regname (ins->dreg), (long)ins->inst_offset);
} else
- g_print (" %s <-", mono_regname_full (ins->dreg, fp));
+ printf (" %s <-", mono_regname_full (ins->dreg, fp));
}
if (spec [MONO_INST_SRC1]) {
gboolean fp = (spec [MONO_INST_SRC1] == 'f');
if (is_soft_reg (ins->sreg1, fp))
- g_print (" R%d", ins->sreg1);
+ printf (" R%d", ins->sreg1);
else if (spec [MONO_INST_SRC1] == 'b')
- g_print (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
+ printf (" [%s + 0x%lx]", mono_arch_regname (ins->sreg1), (long)ins->inst_offset);
else
- g_print (" %s", mono_regname_full (ins->sreg1, fp));
+ printf (" %s", mono_regname_full (ins->sreg1, fp));
}
if (spec [MONO_INST_SRC2]) {
gboolean fp = (spec [MONO_INST_SRC2] == 'f');
if (is_soft_reg (ins->sreg2, fp))
- g_print (" R%d", ins->sreg2);
+ printf (" R%d", ins->sreg2);
else
- g_print (" %s", mono_regname_full (ins->sreg2, fp));
+ printf (" %s", mono_regname_full (ins->sreg2, fp));
}
if (spec [MONO_INST_CLOB])
- g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
- g_print ("\n");
+ printf (" clobbers: %c", spec [MONO_INST_CLOB]);
+ printf ("\n");
}
static void
r = buf;
} else
r = mono_arch_regname (i);
- g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
+ printf ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].killed_in);
}
}
+#endif /* DISABLE_LOGGING */
typedef struct InstList InstList;
};
static inline InstList*
-inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
+inst_list_prepend (guint8 *mem, InstList *list, MonoInst *data)
{
- InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
+ InstList *item = (InstList*)mem;
item->data = data;
item->prev = NULL;
item->next = list;
return item;
}
+static inline void
+insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
+{
+ MonoInst *prev;
+
+ /*
+ * If this function is called multiple times, the new instructions are inserted
+ * in the proper order.
+ */
+
+ if (item->next) {
+ prev = item->next->data;
+
+ while (prev->next != ins)
+ prev = prev->next;
+ to_insert->next = ins;
+ prev->next = to_insert;
+ } else {
+ to_insert->next = ins;
+ }
+
+ /*
+ * insert_after_ins insert the new instruction before item->data, so
+ * we have to modify it to point to the first of the prepended instructions.
+ */
+ if (item->data == ins)
+ item->data = to_insert;
+}
+
+static inline void
+insert_after_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
+{
+ if (item->prev) {
+ while (ins->next != item->prev->data)
+ ins = ins->next;
+ }
+ to_insert->next = ins->next;
+ ins->next = to_insert;
+}
+
/*
* Force the spilling of the variable in the symbolic register 'reg'.
*/
spill = ++cfg->spill_count;
assign [i] = -spill - 1;
if (fp)
- mono_regstate_free_float (cfg->rs, sel);
+ mono_regstate2_free_float (cfg->rs, sel);
else
- mono_regstate_free_int (cfg->rs, sel);
+ mono_regstate2_free_int (cfg->rs, sel);
/* we need to create a spill var and insert a load to sel after the current instruction */
if (fp)
MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
load->dreg = sel;
load->inst_basereg = cfg->frame_reg;
load->inst_offset = mono_spillvar_offset (cfg, spill);
- if (item->prev) {
- while (ins->next != item->prev->data)
- ins = ins->next;
- }
- load->next = ins->next;
- ins->next = load;
- 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)));
+ insert_after_ins (ins, item, load);
+ 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)));
if (fp)
- i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
+ i = mono_regstate2_alloc_float (cfg->rs, regmask (sel));
else
- i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
+ i = mono_regstate2_alloc_int (cfg->rs, regmask (sel));
g_assert (i == sel);
return sel;
symbolic = cfg->rs->isymbolic;
}
- 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));
+ 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));
/* exclude the registers in the current instruction */
- 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))) {
+ 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))) {
if (is_soft_reg (ins->sreg1, fp))
regmask &= ~ (regmask (rassign (cfg, ins->sreg1, fp)));
else
regmask &= ~ (regmask (ins->sreg1));
- DEBUG (g_print ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
+ DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins->sreg1, fp)));
}
- 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))) {
+ 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))) {
if (is_soft_reg (ins->sreg2, fp))
regmask &= ~ (regmask (rassign (cfg, ins->sreg2, fp)));
else
regmask &= ~ (regmask (ins->sreg2));
- DEBUG (g_print ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
+ DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins->sreg2, fp), ins->sreg2));
}
- if ((dreg_is_fp (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
+ if ((dreg_is_fp_ins (ins) == fp) && (reg != ins->dreg) && reg_is_freeable (ins->dreg, fp)) {
regmask &= ~ (regmask (ins->dreg));
- DEBUG (g_print ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
+ DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins->dreg, fp)));
}
- DEBUG (g_print ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
+ DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT "\n", (guint64)regmask));
g_assert (regmask); /* need at least a register we can free */
sel = -1;
/* we should track prev_use and spill the register that's farther */
for (i = 0; i < MONO_MAX_FREGS; ++i) {
if (regmask & (regmask (i))) {
sel = i;
- DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
+ DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel), cfg->rs->fsymbolic [sel]));
break;
}
}
i = cfg->rs->fsymbolic [sel];
spill = ++cfg->spill_count;
cfg->rs->fassign [i] = -spill - 1;
- mono_regstate_free_float (cfg->rs, sel);
+ mono_regstate2_free_float (cfg->rs, sel);
}
else {
for (i = 0; i < MONO_MAX_IREGS; ++i) {
if (regmask & (regmask (i))) {
sel = i;
- DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
+ DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->isymbolic [sel]));
break;
}
}
i = cfg->rs->isymbolic [sel];
spill = ++cfg->spill_count;
cfg->rs->iassign [i] = -spill - 1;
- mono_regstate_free_int (cfg->rs, sel);
+ mono_regstate2_free_int (cfg->rs, sel);
}
/* we need to create a spill var and insert a load to sel after the current instruction */
load->dreg = sel;
load->inst_basereg = cfg->frame_reg;
load->inst_offset = mono_spillvar_offset (cfg, spill);
- if (item->prev) {
- while (ins->next != item->prev->data)
- ins = ins->next;
- }
- load->next = ins->next;
- ins->next = load;
- 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)));
+ insert_after_ins (ins, item, load);
+ 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)));
if (fp)
- i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
+ i = mono_regstate2_alloc_float (cfg->rs, regmask (sel));
else
- i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
+ i = mono_regstate2_alloc_int (cfg->rs, regmask (sel));
g_assert (i == sel);
return sel;
free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
{
if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
- DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
+ DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
- mono_regstate_free_int (cfg->rs, hreg);
+ mono_regstate2_free_int (cfg->rs, hreg);
}
}
{
if (fp) {
if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
- DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
+ DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
- mono_regstate_free_float (cfg->rs, hreg);
+ mono_regstate2_free_float (cfg->rs, hreg);
}
}
else {
if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
- DEBUG (g_print ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
+ DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
- mono_regstate_free_int (cfg->rs, hreg);
+ mono_regstate2_free_int (cfg->rs, hreg);
}
}
}
copy->cil_code = ins->cil_code;
ins->next = copy;
}
- DEBUG (g_print ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
+ DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src, fp), mono_regname_full (dest, fp)));
return copy;
}
store->next = ins->next;
ins->next = store;
}
- 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)));
+ 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)));
return store;
}
-static void
-insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
-{
- MonoInst *prev;
- if (item->next) {
- prev = item->next->data;
-
- while (prev->next != ins)
- prev = prev->next;
- to_insert->next = ins;
- prev->next = to_insert;
- } else {
- to_insert->next = ins;
- }
- /*
- * needed otherwise in the next instruction we can add an ins to the
- * end and that would get past this instruction.
- */
- item->data = to_insert;
-}
-
/* flags used in reginfo->flags */
enum {
MONO_FP_NEEDS_LOAD_SPILL = regmask (0),
MONO_FP_NEEDS_LOAD = regmask (2)
};
-static int
+static inline int
alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info)
{
int val;
if (info && info->preferred_mask) {
- val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
+ val = mono_regstate2_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
if (val >= 0) {
- DEBUG (g_print ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
+ DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
return val;
}
}
- val = mono_regstate_alloc_int (cfg->rs, dest_mask);
+ val = mono_regstate2_alloc_int (cfg->rs, dest_mask);
if (val < 0)
val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
return val;
}
-static int
+static inline int
alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg)
{
int val;
- val = mono_regstate_alloc_float (cfg->rs, dest_mask);
+ val = mono_regstate2_alloc_float (cfg->rs, dest_mask);
if (val < 0) {
val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
return val;
}
-static int
+static inline int
alloc_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_mask, int sym_reg, RegTrack *info, gboolean fp)
{
if (fp)
{
MonoInst *ins;
MonoRegState *rs = cfg->rs;
- int i, val, fpcount;
+ int i, val, fpcount, ins_count;
RegTrack *reginfo, *reginfof;
RegTrack *reginfo1, *reginfo2, *reginfod;
InstList *tmp, *reversed = NULL;
GList *fspill_list = NULL;
gboolean fp;
int fspill = 0;
+ guint8 *inst_list, *mem;
+#if MONO_ARCH_USE_FPSTACK
+ gboolean need_fpstack = (use_fpstack && bb->max_freg > MONO_MAX_FREGS);
+#endif
if (!bb->code)
return;
rs->next_vireg = bb->max_ireg;
rs->next_vfreg = bb->max_freg;
- mono_regstate_assign (rs);
- reginfo = g_malloc0 (sizeof (RegTrack) * rs->next_vireg);
- reginfof = g_malloc0 (sizeof (RegTrack) * rs->next_vfreg);
+ mono_regstate2_assign (rs);
+
rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
/*if (cfg->opt & MONO_OPT_COPYPROP)
local_copy_prop (cfg, ins);*/
+ if (cfg->reginfo && cfg->reginfo_len < rs->next_vireg) {
+ cfg->reginfo = NULL;
+ }
+ reginfo = cfg->reginfo;
+ if (!reginfo) {
+ cfg->reginfo_len = MAX (256, rs->next_vireg * 2);
+ reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
+ }
+ else
+ g_assert (cfg->reginfo_len >= rs->next_vireg);
+
+ if (cfg->reginfof && cfg->reginfof_len < rs->next_vfreg) {
+ cfg->reginfof = NULL;
+ }
+ reginfof = cfg->reginfof;
+ if (!reginfof) {
+ cfg->reginfof_len = MAX (256, rs->next_vireg * 2);
+ reginfof = cfg->reginfof = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfof_len);
+ }
+ else
+ g_assert (cfg->reginfof_len >= rs->next_vfreg);
+
+ memset (reginfo, 0, rs->next_vireg * sizeof (RegTrack));
+ memset (reginfof, 0, rs->next_vfreg * sizeof (RegTrack));
+
+ ins_count = 0;
+ for (ins = bb->code; ins; ins = ins->next) {
+ spec = ins_spec [ins->opcode];
+
+ ins_count ++;
+ }
+
+ if (cfg->reverse_inst_list && (cfg->reverse_inst_list_len < ins_count)) {
+ cfg->reverse_inst_list = NULL;
+ }
+
+ inst_list = cfg->reverse_inst_list;
+ if (!inst_list) {
+ cfg->reverse_inst_list_len = MAX (ins_count, 1024);
+ inst_list = cfg->reverse_inst_list = mono_mempool_alloc (cfg->mempool, cfg->reverse_inst_list_len * sizeof (InstList));
+ }
+ mem = inst_list;
+
i = 1;
fpcount = 0;
- DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
+ DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb->block_num));
/* forward pass on the instructions to collect register liveness info */
- while (ins) {
+ for (ins = bb->code; ins; ins = ins->next) {
spec = ins_spec [ins->opcode];
- if (!spec) {
+ if (G_UNLIKELY (!spec)) {
g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
}
/*
* TRACK FP STACK
*/
- if (use_fpstack) {
+#if MONO_ARCH_USE_FPSTACK
+ if (need_fpstack) {
GList *spill;
if (spec [MONO_INST_SRC1] == 'f') {
fpcount--;
}
- if (dreg_is_fp (ins)) {
+ if (dreg_is_fp (spec)) {
if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
reginfof [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
}
}
}
+#endif
if (spec [MONO_INST_SRC1]) {
if (spec [MONO_INST_SRC1] == 'f')
reginfo1 = reginfof;
else
reginfo1 = reginfo;
- reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
- reginfo1 [ins->sreg1].last_use = i;
+ //reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
+ //reginfo1 [ins->sreg1].last_use = i;
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
/* The virtual register is allocated sequentially */
- reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
- reginfo1 [ins->sreg1 + 1].last_use = i;
+ //reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
+ //reginfo1 [ins->sreg1 + 1].last_use = i;
if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
reginfo1 [ins->sreg1 + 1].born_in = i;
}
reginfo2 = reginfof;
else
reginfo2 = reginfo;
- reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
- reginfo2 [ins->sreg2].last_use = i;
+ //reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
+ //reginfo2 [ins->sreg2].last_use = i;
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
/* The virtual register is allocated sequentially */
- reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
- reginfo2 [ins->sreg2 + 1].last_use = i;
+ //reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
+ //reginfo2 [ins->sreg2 + 1].last_use = i;
if (reginfo2 [ins->sreg2 + 1].born_in == 0 || reginfo2 [ins->sreg2 + 1].born_in > i)
reginfo2 [ins->sreg2 + 1].born_in = i;
}
if (spec [MONO_INST_DEST]) {
int dest_dreg;
- if (dreg_is_fp (ins))
+ if (dreg_is_fp (spec))
reginfod = reginfof;
else
reginfod = reginfo;
if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
reginfod [ins->dreg].killed_in = i;
- reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
- reginfod [ins->dreg].last_use = i;
+ //reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
+ //reginfod [ins->dreg].last_use = i;
if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
reginfod [ins->dreg].born_in = i;
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
/* The virtual register is allocated sequentially */
- reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
- reginfod [ins->dreg + 1].last_use = i;
+ //reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
+ //reginfod [ins->dreg + 1].last_use = i;
if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
reginfod [ins->dreg + 1].born_in = i;
if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
hreg = regpair >> 24;
reg = regpair & 0xffffff;
- reginfo [reg].prev_use = reginfo [reg].last_use;
- reginfo [reg].last_use = i;
+ //reginfo [reg].prev_use = reginfo [reg].last_use;
+ //reginfo [reg].last_use = i;
list = g_slist_next (list);
}
hreg = regpair >> 24;
reg = regpair & 0xffffff;
- reginfof [reg].prev_use = reginfof [reg].last_use;
- reginfof [reg].last_use = i;
+ //reginfof [reg].prev_use = reginfof [reg].last_use;
+ //reginfof [reg].last_use = i;
list = g_slist_next (list);
}
}
}
- reversed = inst_list_prepend (cfg->mempool, reversed, ins);
+ reversed = inst_list_prepend (mem, reversed, ins);
+ mem += sizeof (InstList);
++i;
- ins = ins->next;
}
// todo: check if we have anything left on fp stack, in verify mode?
int dest_dreg, dest_sreg1, dest_sreg2, clob_reg;
int dreg_high, sreg1_high;
regmask_t dreg_mask, sreg1_mask, sreg2_mask, mask;
+ regmask_t dreg_fixed_mask, sreg1_fixed_mask, sreg2_fixed_mask;
const unsigned char *ip;
--i;
ins = tmp->data;
dest_dreg = -1;
dest_sreg1 = -1;
dest_sreg2 = -1;
- dreg_mask = dreg_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
- sreg1_mask = sreg1_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
- sreg2_mask = sreg2_is_fp (ins) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
+ dreg_mask = dreg_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
+ sreg1_mask = sreg1_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
+ sreg2_mask = sreg2_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
- DEBUG (g_print ("processing:"));
+ DEBUG (printf ("processing:"));
DEBUG (print_ins (i, ins));
ip = ins->cil_code;
clob_reg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_CLOB]);
sreg2_mask &= ~ (MONO_ARCH_INST_SREG2_MASK (spec));
+#ifdef MONO_ARCH_INST_FIXED_MASK
+ sreg1_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC1]);
+ sreg2_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_SRC2]);
+ dreg_fixed_mask = MONO_ARCH_INST_FIXED_MASK (spec [MONO_INST_DEST]);
+#else
+ sreg1_fixed_mask = sreg2_fixed_mask = dreg_fixed_mask = 0;
+#endif
+
/*
* TRACK FP STACK
*/
- if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
- if (dreg_is_fp (ins)) {
+#if MONO_ARCH_USE_FPSTACK
+ if (need_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
+ if (dreg_is_fp (spec)) {
if (reginfof [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
GList *spill_node;
MonoInst *store;
}
}
}
+#endif
/*
* TRACK FIXED SREG2
insert_before_ins (ins, tmp, copy);
}
else {
- DEBUG (g_print ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
+ DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
}
} else {
int new_dest;
new_dest = alloc_int_reg (cfg, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg]);
g_assert (new_dest >= 0);
- DEBUG (g_print ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
+ DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins->dreg, mono_arch_regname (new_dest), mono_arch_regname (dest_sreg2)));
prev_dreg = ins->dreg;
assign_ireg (cfg, rs, ins->dreg, new_dest);
}
if (need_spill) {
- DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
+ DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
- mono_regstate_free_int (rs, dest_sreg2);
+ mono_regstate2_free_int (rs, dest_sreg2);
}
if (!is_global_ireg (ins->sreg2))
/*
* TRACK DREG
*/
- fp = dreg_is_fp (ins);
+ fp = dreg_is_fp (spec);
if (spec [MONO_INST_DEST] && (!fp || (fp && !use_fpstack)) && is_soft_reg (ins->dreg, fp))
prev_dreg = ins->dreg;
dreg_mask &= ~ (regmask (dest_sreg1));
if (dest_sreg2 != -1)
dreg_mask &= ~ (regmask (dest_sreg2));
+
+ val = rassign (cfg, ins->dreg, fp);
+ if (is_soft_reg (ins->dreg, fp) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
+ /* DREG is already allocated to a register needed for sreg1 */
+ get_register_force_spilling (cfg, tmp, ins, ins->dreg, FALSE);
+ mono_regstate2_free_int (rs, val);
+ }
}
/*
}
}
+ if (dreg_fixed_mask) {
+ g_assert (!fp);
+ if (is_global_ireg (ins->dreg)) {
+ /*
+ * The argument is already in a hard reg, but that reg is
+ * not usable by this instruction, so allocate a new one.
+ */
+ val = mono_regstate2_alloc_int (rs, dreg_fixed_mask);
+ if (val < 0)
+ val = get_register_spilling (cfg, tmp, ins, dreg_fixed_mask, -1, fp);
+ mono_regstate2_free_int (rs, val);
+ dest_dreg = val;
+
+ /* Fall through */
+ }
+ else
+ dreg_mask &= dreg_fixed_mask;
+ }
+
if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->dreg, fp))) {
if (dest_dreg != -1)
dreg_mask = (regmask (dest_dreg));
create_spilled_store (cfg, spill, val, prev_dreg, ins, fp);
}
- DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
+ DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, fp), ins->dreg));
ins->dreg = val;
}
/* the register gets spilled after this inst */
spill = -val -1;
}
- val = mono_regstate_alloc_int (rs, mask);
+ val = mono_regstate2_alloc_int (rs, mask);
if (val < 0)
val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
if (spill)
}
else {
if (! (mask & (regmask (val)))) {
- val = mono_regstate_alloc_int (rs, mask);
+ val = mono_regstate2_alloc_int (rs, mask);
if (val < 0)
val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
/* Reallocate hreg to the correct register */
create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
- mono_regstate_free_int (rs, rs->iassign [reg2]);
+ mono_regstate2_free_int (rs, rs->iassign [reg2]);
}
}
- DEBUG (g_print ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
+ DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2));
assign_reg (cfg, rs, reg2, val, fp);
dreg_high = val;
ins->unused = val;
if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
- DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
- mono_regstate_free_int (rs, val);
+ DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
+ mono_regstate2_free_int (rs, val);
}
}
*/
int dreg = rassign (cfg, prev_dreg, fp);
g_assert (dreg >= 0);
- 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));
+ DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, (fp ? reginfof : reginfo) [prev_dreg].born_in));
if (fp)
- mono_regstate_free_float (rs, dreg);
+ mono_regstate2_free_float (rs, dreg);
else
- mono_regstate_free_int (rs, dreg);
+ mono_regstate2_free_int (rs, dreg);
}
if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
* TRACK CLOBBERING
*/
if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
- DEBUG (g_print ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
+ DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
- mono_regstate_free_int (rs, clob_reg);
+ mono_regstate2_free_int (rs, clob_reg);
}
if (spec [MONO_INST_CLOB] == 'c') {
* Need to avoid spilling the dreg since the dreg is not really
* clobbered by the call.
*/
- if ((prev_dreg != -1) && !dreg_is_fp (ins))
- dreg = rassign (cfg, prev_dreg, dreg_is_fp (ins));
+ if ((prev_dreg != -1) && !dreg_is_fp (spec))
+ dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
else
dreg = -1;
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]))
- dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (ins));
+ dreg2 = rassign (cfg, prev_dreg + 1, dreg_is_fp (spec));
else
dreg2 = -1;
s = regmask (j);
if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
- mono_regstate_free_int (rs, j);
+ mono_regstate2_free_int (rs, j);
}
}
if (!use_fpstack) {
clob_mask = MONO_ARCH_CALLEE_FREGS;
- if ((prev_dreg != -1) && dreg_is_fp (ins))
- dreg = rassign (cfg, prev_dreg, dreg_is_fp (ins));
+ if ((prev_dreg != -1) && dreg_is_fp (spec))
+ dreg = rassign (cfg, prev_dreg, dreg_is_fp (spec));
else
dreg = -1;
s = regmask (j);
if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
- mono_regstate_free_float (rs, j);
+ mono_regstate2_free_float (rs, j);
}
}
}
sreg1_mask &= ~(regmask (hreg));
- DEBUG (g_print ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
+ DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg), reg));
list = g_slist_next (list);
}
- g_slist_free (call->out_ireg_args);
}
list = call->out_freg_args;
assign_reg (cfg, rs, reg, hreg, TRUE);
- DEBUG (g_print ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
+ DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg), reg));
list = g_slist_next (list);
}
}
- if (call->out_freg_args)
- g_slist_free (call->out_freg_args);
}
/*
* TRACK SREG1
*/
- fp = sreg1_is_fp (ins);
+ fp = sreg1_is_fp (spec);
if ((!fp || (fp && !use_fpstack))) {
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST]) && (spec [MONO_INST_CLOB] == '1')) {
g_assert (is_soft_reg (ins->sreg1, fp));
/* To simplify things, we allocate the same regpair to sreg1 and dreg */
if (dest_sreg1 != -1)
g_assert (dest_sreg1 == ins->dreg);
- val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
+ val = mono_regstate2_alloc_int (rs, regmask (ins->dreg));
g_assert (val >= 0);
assign_reg (cfg, rs, ins->sreg1, val, fp);
- DEBUG (g_print ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
+ DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
- val = mono_regstate_alloc_int (rs, regmask (dreg_high));
+ val = mono_regstate2_alloc_int (rs, regmask (dreg_high));
g_assert (val >= 0);
assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
- DEBUG (g_print ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
+ DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val, fp), ins->sreg1 + 1));
/* Skip rest of this section */
dest_sreg1 = -1;
}
+ if (sreg1_fixed_mask) {
+ g_assert (!fp);
+ if (is_global_ireg (ins->sreg1)) {
+ /*
+ * The argument is already in a hard reg, but that reg is
+ * not usable by this instruction, so allocate a new one.
+ */
+ val = mono_regstate2_alloc_int (rs, sreg1_fixed_mask);
+ if (val < 0)
+ val = get_register_spilling (cfg, tmp, ins, sreg1_fixed_mask, -1, fp);
+ mono_regstate2_free_int (rs, val);
+ dest_sreg1 = val;
+
+ /* Fall through to the dest_sreg1 != -1 case */
+ }
+ else
+ sreg1_mask &= sreg1_fixed_mask;
+ }
+
if (dest_sreg1 != -1) {
sreg1_mask = regmask (dest_sreg1);
if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
- DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
+ DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
- mono_regstate_free_int (rs, dest_sreg1);
+ mono_regstate2_free_int (rs, dest_sreg1);
}
if (is_global_ireg (ins->sreg1)) {
/* The argument is already in a hard reg, need to copy */
spill = -val -1;
}
- if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (!is_global_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
+ if (((ins->opcode == OP_MOVE) || (ins->opcode == OP_SETREG)) && !spill && !fp && (is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg))))) {
/*
* Allocate the same hreg to sreg1 as well so the
* peephole can get rid of the move.
val = alloc_reg (cfg, tmp, ins, sreg1_mask, ins->sreg1, ®info [ins->sreg1], fp);
assign_reg (cfg, rs, ins->sreg1, val, fp);
- DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
+ DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
if (spill) {
MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, fp);
}
}
else if ((dest_sreg1 != -1) && (dest_sreg1 != val)) {
- g_assert_not_reached ();
+ create_copy_ins (cfg, dest_sreg1, val, ins, ip, fp);
}
ins->sreg1 = val;
/* the register gets spilled after this inst */
spill = -val -1;
}
- val = mono_regstate_alloc_int (rs, mask);
+ val = mono_regstate2_alloc_int (rs, mask);
if (val < 0)
val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
if (spill)
/* FIXME: */
g_assert_not_reached ();
#if 0
- val = mono_regstate_alloc_int (rs, mask);
+ val = mono_regstate2_alloc_int (rs, mask);
if (val < 0)
val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
/* Reallocate hreg to the correct register */
create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
- mono_regstate_free_int (rs, rs->iassign [reg2]);
+ mono_regstate2_free_int (rs, rs->iassign [reg2]);
#endif
}
}
sreg1_high = val;
- DEBUG (g_print ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
+ DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2));
assign_reg (cfg, rs, reg2, val, fp);
}
/* Handle dreg==sreg1 */
- if (((dreg_is_fp (ins) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
+ if (((dreg_is_fp (spec) && spec [MONO_INST_SRC1] == 'f' && !use_fpstack) || spec [MONO_INST_CLOB] == '1') && ins->dreg != ins->sreg1) {
MonoInst *sreg2_copy = NULL;
MonoInst *copy;
gboolean fp = (spec [MONO_INST_SRC1] == 'f');
*/
int reg2 = alloc_reg (cfg, tmp, ins, dreg_mask, ins->sreg2, NULL, fp);
- DEBUG (g_print ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
+ DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins->sreg2, fp), mono_regname_full (reg2, fp)));
sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, ip, fp);
prev_sreg2 = ins->sreg2 = reg2;
if (fp)
- mono_regstate_free_float (rs, reg2);
+ mono_regstate2_free_float (rs, reg2);
else
- mono_regstate_free_int (rs, reg2);
+ mono_regstate2_free_int (rs, reg2);
}
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
g_assert (dreg_high == sreg1_high);
}
- DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
+ DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins->sreg1, fp), mono_regname_full (ins->dreg, fp)));
copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL, ip, fp);
insert_before_ins (ins, tmp, copy);
/*
* TRACK SREG2
*/
- fp = sreg2_is_fp (ins);
+ fp = sreg2_is_fp (spec);
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2]))
g_assert_not_reached ();
if ((!fp || (fp && !use_fpstack)) && (is_soft_reg (ins->sreg2, fp))) {
}
val = alloc_reg (cfg, tmp, ins, sreg2_mask, ins->sreg2, ®info [ins->sreg2], fp);
assign_reg (cfg, rs, ins->sreg2, val, fp);
- DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
- if (spill)
- create_spilled_store (cfg, spill, val, prev_sreg2, ins, fp);
+ DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val, fp), ins->sreg2));
+ if (spill) {
+ MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg2, NULL, fp);
+ /*
+ * Need to insert before the instruction since it can
+ * overwrite sreg2.
+ */
+ insert_before_ins (ins, tmp, store);
+ }
}
ins->sreg2 = val;
}
}
/*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
- DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
- mono_regstate_free_int (rs, ins->sreg1);
+ DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
+ mono_regstate2_free_int (rs, ins->sreg1);
}
if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
- DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
- mono_regstate_free_int (rs, ins->sreg2);
+ DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
+ mono_regstate2_free_int (rs, ins->sreg2);
}*/
DEBUG (print_ins (i, ins));
tmp = tmp->next;
}
- g_free (reginfo);
- g_free (reginfof);
g_list_free (fspill_list);
}