static const int regbank_size [] = {
MONO_MAX_IREGS,
MONO_MAX_FREGS,
+ MONO_MAX_IREGS,
MONO_MAX_XREGS
};
static const int regbank_load_ops [] = {
OP_LOADR_MEMBASE,
OP_LOADR8_MEMBASE,
+ OP_LOADR_MEMBASE,
OP_LOADX_MEMBASE
};
static const int regbank_store_ops [] = {
OP_STORER_MEMBASE_REG,
OP_STORER8_MEMBASE_REG,
+ OP_STORER_MEMBASE_REG,
OP_STOREX_MEMBASE
};
static const int regbank_move_ops [] = {
OP_MOVE,
OP_FMOVE,
+ OP_MOVE,
OP_XMOVE
};
static const regmask_t regbank_callee_saved_regs [] = {
MONO_ARCH_CALLEE_SAVED_REGS,
MONO_ARCH_CALLEE_SAVED_FREGS,
+ MONO_ARCH_CALLEE_SAVED_REGS,
MONO_ARCH_CALLEE_SAVED_XREGS,
};
static const regmask_t regbank_callee_regs [] = {
MONO_ARCH_CALLEE_REGS,
MONO_ARCH_CALLEE_FREGS,
+ MONO_ARCH_CALLEE_REGS,
MONO_ARCH_CALLEE_XREGS,
};
static const int regbank_spill_var_size[] = {
sizeof (mgreg_t),
sizeof (double),
+ sizeof (mgreg_t),
16 /*FIXME make this a constant. Maybe MONO_ARCH_SIMD_VECTOR_SIZE? */
};
memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
- rs->symbolic [0] = rs->isymbolic;
- rs->symbolic [1] = rs->fsymbolic;
+ rs->symbolic [MONO_REG_INT] = rs->isymbolic;
+ rs->symbolic [MONO_REG_DOUBLE] = rs->fsymbolic;
#ifdef MONO_ARCH_NEED_SIMD_BANK
memset (rs->xsymbolic, 0, MONO_MAX_XREGS * sizeof (rs->xsymbolic [0]));
- rs->symbolic [2] = rs->xsymbolic;
+ rs->symbolic [MONO_REG_SIMD] = rs->xsymbolic;
#endif
}
g_assert (bank < MONO_NUM_REGBANKS);
- new_info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo) * new_len);
+ new_info = mono_mempool_alloc0 (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)
int i, sel, spill;
int *symbolic;
MonoRegState *rs = cfg->rs;
+ gboolean ref = vreg_is_ref (cfg, reg);
symbolic = rs->symbolic [bank];
sel = rs->vassign [reg];
MONO_INST_NEW (cfg, load, regbank_load_ops [bank]);
load->dreg = sel;
load->inst_basereg = cfg->frame_reg;
- load->inst_offset = mono_spillvar_offset (cfg, spill, bank);
+ load->inst_offset = mono_spillvar_offset (cfg, spill, ref ? MONO_REG_INT_REF : bank);
insert_after_ins (bb, ins, last, 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, bank)));
if (G_UNLIKELY (bank))
int sregs [MONO_MAX_SRC_REGS];
int *symbolic;
MonoRegState *rs = cfg->rs;
+ gboolean is_ref;
symbolic = rs->symbolic [bank];
mono_regstate_free_int (rs, sel);
}
+ is_ref = vreg_is_ref (cfg, i);
+
/* we need to create a spill var and insert a load to sel after the current instruction */
MONO_INST_NEW (cfg, load, regbank_load_ops [bank]);
load->dreg = sel;
load->inst_basereg = cfg->frame_reg;
- load->inst_offset = mono_spillvar_offset (cfg, spill, bank);
+ load->inst_offset = mono_spillvar_offset (cfg, spill, is_ref ? MONO_REG_INT_REF : bank);
insert_after_ins (bb, ins, last, 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, bank)));
if (G_UNLIKELY (bank))
return copy;
}
-static MonoInst*
-create_spilled_store (MonoCompile *cfg, MonoBasicBlock *bb, int spill, int reg, int prev_reg, MonoInst **last, MonoInst *ins, int bank)
+static void
+create_spilled_store (MonoCompile *cfg, MonoBasicBlock *bb, int spill, int reg, int prev_reg, MonoInst **last, MonoInst *ins, MonoInst *insert_before, int bank)
{
- MonoInst *store;
+ MonoInst *store, *def;
+ gboolean is_ref = vreg_is_ref (cfg, prev_reg);
+
MONO_INST_NEW (cfg, store, regbank_store_ops [bank]);
store->sreg1 = reg;
store->inst_destbasereg = cfg->frame_reg;
- store->inst_offset = mono_spillvar_offset (cfg, spill, bank);
+ store->inst_offset = mono_spillvar_offset (cfg, spill, is_ref ? MONO_REG_INT_REF : bank);
if (ins) {
mono_bblock_insert_after_ins (bb, ins, store);
*last = store;
+ } else if (insert_before) {
+ insert_before_ins (bb, insert_before, store);
+ } else {
+ g_assert_not_reached ();
}
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, bank)));
- return store;
+
+ if (is_ref && cfg->compute_gc_maps) {
+ g_assert (prev_reg != -1);
+ MONO_INST_NEW (cfg, def, OP_GC_SPILL_SLOT_LIVENESS_DEF);
+ def->inst_c0 = spill;
+ mono_bblock_insert_after_ins (bb, store, def);
+ *last = def;
+ }
}
/* flags used in reginfo->flags */
if (need_assign) {
if (rs->vassign [sreg] < -1) {
- MonoInst *store;
int spill;
/* Need to emit a spill store */
spill = - rs->vassign [sreg] - 1;
- store = create_spilled_store (cfg, bb, spill, dest_sreg, sreg, tmp, NULL, bank);
- insert_before_ins (bb, ins, store);
+ create_spilled_store (cfg, bb, spill, dest_sreg, sreg, tmp, NULL, ins, bank);
}
/* force-set sreg2 */
assign_reg (cfg, rs, sregs [j], dest_sreg, 0);
val = alloc_reg (cfg, bb, tmp, ins, dreg_mask, ins->dreg, ®info [ins->dreg], bank);
assign_reg (cfg, rs, ins->dreg, val, bank);
if (spill)
- create_spilled_store (cfg, bb, spill, val, prev_dreg, tmp, ins, bank);
+ create_spilled_store (cfg, bb, spill, val, prev_dreg, tmp, ins, NULL, bank);
}
DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val, bank), ins->dreg));
if (val < 0)
val = get_register_spilling (cfg, bb, tmp, ins, mask, reg2, bank);
if (spill)
- create_spilled_store (cfg, bb, spill, val, reg2, tmp, ins, bank);
+ create_spilled_store (cfg, bb, spill, val, reg2, tmp, ins, NULL, bank);
}
else {
if (! (mask & (regmask (val)))) {
DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val, bank), sregs [0]));
if (spill) {
- MonoInst *store = create_spilled_store (cfg, bb, spill, val, prev_sregs [0], tmp, NULL, bank);
/*
* Need to insert before the instruction since it can
* overwrite sreg1.
*/
- insert_before_ins (bb, ins, store);
+ create_spilled_store (cfg, bb, spill, val, prev_sregs [0], tmp, NULL, ins, bank);
}
}
else if ((dest_sregs [0] != -1) && (dest_sregs [0] != val)) {
assign_reg (cfg, rs, sregs [j], val, bank);
DEBUG (printf ("\tassigned sreg%d %s to R%d\n", j + 1, mono_regname_full (val, bank), sregs [j]));
if (spill) {
- MonoInst *store = create_spilled_store (cfg, bb, spill, val, prev_sregs [j], tmp, NULL, bank);
/*
* Need to insert before the instruction since it can
* overwrite sreg2.
*/
- insert_before_ins (bb, ins, store);
+ create_spilled_store (cfg, bb, spill, val, sregs [j], tmp, NULL, ins, bank);
}
}
sregs [j] = val;
* means cfa+0, 1 means cfa-4/8, etc.
*/
GSList *stack_slots_from_cfa;
+ /* Same for stack slots relative to the frame pointer */
+ GSList *stack_slots_from_fp;
/* Number of slots in the map */
int nslots;
gboolean *starts_pinned;
/* Min and Max offsets of the stack frame relative to fp */
int min_offset, max_offset;
+ /* Same for the locals area */
+ int locals_min_offset, locals_max_offset;
} MonoCompileGC;
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
if (COMPILE_LLVM (cfg))
return;
+#if 1
+ /* Debugging support */
+ {
+ static int precise_count;
+
+ precise_count ++;
+ if (getenv ("MONO_GCMAP_COUNT")) {
+ if (precise_count == atoi (getenv ("MONO_GCMAP_COUNT")))
+ printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
+ if (precise_count > atoi (getenv ("MONO_GCMAP_COUNT")))
+ return;
+ }
+ }
+#endif
+
cfg->compute_gc_maps = TRUE;
cfg->gc_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoCompileGC));
}
+/*
+ * mini_gc_set_slot_type_from_fp:
+ *
+ * Set the GC slot type of the stack slot identified by SLOT_OFFSET, which should be
+ * relative to the frame pointer. By default, all stack slots are type PIN, so there is no
+ * need to call this function for those slots.
+ */
+void
+mini_gc_set_slot_type_from_fp (MonoCompile *cfg, int slot_offset, StackSlotType type)
+{
+ MonoCompileGC *gcfg = (MonoCompileGC*)cfg->gc_info;
+
+ if (!cfg->compute_gc_maps)
+ return;
+
+ g_assert (slot_offset % sizeof (mgreg_t) == 0);
+
+ gcfg->stack_slots_from_fp = g_slist_prepend_mempool (cfg->mempool, gcfg->stack_slots_from_fp, GINT_TO_POINTER (((slot_offset) << 16) | type));
+}
+
/*
* mini_gc_set_slot_type_from_cfa:
*
* If type is STACK_REF, the slot is assumed to be live from the end of the prolog until
* the end of the method. By default, all stack slots are type PIN, so there is no need to
* call this function for those slots.
- * FIXME: Add a variant for fp relative offsets.
*/
void
mini_gc_set_slot_type_from_cfa (MonoCompile *cfg, int slot_offset, StackSlotType type)
static inline void
set_slot (MonoCompileGC *gcfg, int pos, StackSlotType val)
{
- g_assert (pos < gcfg->nslots);
+ g_assert (pos >= 0 && pos < gcfg->nslots);
gcfg->slots [pos] = val;
}
+static inline int
+fp_offset_to_slot (MonoCompile *cfg, int offset)
+{
+ MonoCompileGC *gcfg = cfg->gc_info;
+
+ return (offset - gcfg->min_offset) / sizeof (mgreg_t);
+}
+
+static void
+process_spill_slots (MonoCompile *cfg)
+{
+ MonoCompileGC *gcfg = cfg->gc_info;
+ MonoBasicBlock *bb;
+ GSList *l;
+
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ /*
+ * Extend the live interval for the GC tracked spill slots
+ * defined in this bblock.
+ */
+ for (l = bb->spill_slot_defs; l; l = l->next) {
+ MonoInst *def = l->data;
+ int spill_slot = def->inst_c0;
+ int offset = cfg->spill_info [MONO_REG_INT_REF][spill_slot].offset;
+ int slot = fp_offset_to_slot (cfg, offset);
+ MonoLiveInterval *interval;
+
+ set_slot (gcfg, slot, SLOT_REF);
+
+ interval = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLiveInterval));
+ mono_linterval_add_range (cfg, interval, def->backend.pc_offset, bb->native_offset + bb->native_length);
+ gcfg->live_intervals [slot] = g_slist_prepend_mempool (cfg->mempool, gcfg->live_intervals [slot], interval);
+
+ if (cfg->verbose_level > 1)
+ printf ("\tref spill slot at fp+0x%x (slot = %d)\n", offset, slot);
+ }
+ }
+}
+
/*
* process_other_slots:
*
{
MonoCompileGC *gcfg = cfg->gc_info;
GSList *l;
-
+
+ /* Relative to the CFA */
for (l = gcfg->stack_slots_from_cfa; l; l = l->next) {
guint data = GPOINTER_TO_UINT (l->data);
int slot = data >> 16;
printf ("\tnoref at fp+0x%x (slot = %d) (cfa - 0x%x)\n", (int)(fp_slot * sizeof (mgreg_t)), fp_slot, (int)(slot * sizeof (mgreg_t)));
}
}
+
+ /* Relative to the FP */
+ for (l = gcfg->stack_slots_from_fp; l; l = l->next) {
+ guint data = GPOINTER_TO_INT (l->data);
+ int offset = data >> 16;
+ StackSlotType type = data & 0xff;
+ int slot;
+
+ slot = fp_offset_to_slot (cfg, offset);
+
+ set_slot (gcfg, slot, type);
+
+ /* Liveness for these slots is handled by process_spill_slots () */
+
+ if (cfg->verbose_level > 1) {
+ if (type == SLOT_REF)
+ printf ("\tref at fp+0x%x (slot = %d)\n", offset, slot);
+ }
+ }
}
static void
process_locals (MonoCompile *cfg)
{
- int i;
+ int i, locals_min_slot, locals_max_slot;
MonoBasicBlock *bb;
MonoInst *tmp;
int *pc_offsets;
MonoCompileGC *gcfg = cfg->gc_info;
GSList **live_intervals = gcfg->live_intervals;
gboolean *starts_pinned = gcfg->starts_pinned;
+ int locals_min_offset = gcfg->locals_min_offset;
+ int locals_max_offset = gcfg->locals_max_offset;
+
+ /* Slots for locals are NOREF by default */
+ locals_min_slot = (locals_min_offset - gcfg->min_offset) / sizeof (gpointer);
+ locals_max_slot = (locals_max_offset - gcfg->min_offset) / sizeof (gpointer);
+ for (i = locals_min_slot; i < locals_max_slot; ++i)
+ set_slot (gcfg, i, SLOT_NOREF);
/*
* Compute the offset where variables are initialized in the first bblock, if any.
if (ins->inst_offset % sizeof (gpointer) != 0)
continue;
- pos = (ins->inst_offset - gcfg->min_offset) / sizeof (gpointer);
+ pos = fp_offset_to_slot (cfg, ins->inst_offset);
if (MONO_TYPE_ISSTRUCT (t)) {
int numbits = 0, j;
}
}
+static void
+compute_frame_size (MonoCompile *cfg)
+{
+ int i, locals_min_offset, locals_max_offset, cfa_min_offset, cfa_max_offset;
+ int min_offset, max_offset;
+ MonoCompileGC *gcfg = cfg->gc_info;
+ MonoMethodSignature *sig = mono_method_signature (cfg->method);
+
+ /* Compute min/max offsets from the fp */
+
+ /* Locals */
+#ifdef TARGET_AMD64
+ locals_min_offset = ALIGN_TO (cfg->locals_min_stack_offset, sizeof (gpointer));
+ locals_max_offset = cfg->locals_max_stack_offset;
+#else
+ /* min/max stack offset needs to be computed in mono_arch_allocate_vars () */
+ NOT_IMPLEMENTED;
+#endif
+
+ locals_min_offset = ALIGN_TO (locals_min_offset, sizeof (gpointer));
+ locals_max_offset = ALIGN_TO (locals_max_offset, sizeof (gpointer));
+
+ min_offset = locals_min_offset;
+ max_offset = locals_max_offset;
+
+ /* Arguments */
+ for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+ MonoInst *ins = cfg->args [i];
+
+ if (ins->opcode == OP_REGOFFSET)
+ min_offset = MIN (min_offset, ins->inst_offset);
+ }
+
+ /* Cfa slots */
+ g_assert (cfg->frame_reg == cfg->cfa_reg);
+ g_assert (cfg->cfa_offset > 0);
+ cfa_min_offset = 0;
+ cfa_max_offset = cfg->cfa_offset;
+
+ min_offset = MIN (min_offset, cfa_min_offset);
+ max_offset = MAX (max_offset, cfa_max_offset);
+
+ /* Spill slots */
+ if (!(cfg->flags & MONO_CFG_HAS_SPILLUP)) {
+ int stack_offset = ALIGN_TO (cfg->stack_offset, sizeof (mgreg_t));
+ min_offset = MIN (min_offset, (-stack_offset));
+ }
+
+ gcfg->min_offset = min_offset;
+ gcfg->max_offset = max_offset;
+ gcfg->locals_min_offset = locals_min_offset;
+ gcfg->locals_max_offset = locals_max_offset;
+}
+
void
mini_gc_create_gc_map (MonoCompile *cfg)
{
GCMap *map;
- int i, locals_min_offset, locals_max_offset, cfa_min_offset, cfa_max_offset;
- int min_offset, max_offset, locals_min_slot, locals_max_slot;
- int nslots, alloc_size;
+ int i, nslots, alloc_size;
int ntypes [16];
StackSlotType *slots = NULL;
GSList **live_intervals;
gboolean *starts_pinned;
gboolean has_ref_slots, has_pin_slots;
MonoCompileGC *gcfg = cfg->gc_info;
- MonoMethodSignature *sig = mono_method_signature (cfg->method);
+
+ if (!cfg->compute_gc_maps)
+ return;
/*
* Since we currently don't use GC safe points, we need to create GC maps which
return;
mono_analyze_liveness_gc (cfg);
-
- /* Compute min/max offsets from the fp */
-
- /* Locals */
-#ifdef TARGET_AMD64
- locals_min_offset = ALIGN_TO (cfg->locals_min_stack_offset, sizeof (gpointer));
- locals_max_offset = cfg->locals_max_stack_offset;
-#else
- /* min/max stack offset needs to be computed in mono_arch_allocate_vars () */
- NOT_IMPLEMENTED;
-#endif
-
- locals_min_offset = ALIGN_TO (locals_min_offset, sizeof (gpointer));
- locals_max_offset = ALIGN_TO (locals_max_offset, sizeof (gpointer));
-
- min_offset = locals_min_offset;
- max_offset = locals_max_offset;
-
- /* Arguments */
- for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
- MonoInst *ins = cfg->args [i];
-
- if (ins->opcode == OP_REGOFFSET)
- min_offset = MIN (min_offset, ins->inst_offset);
- }
-
- /* Cfa slots */
- g_assert (cfg->frame_reg == cfg->cfa_reg);
- g_assert (cfg->cfa_offset > 0);
- cfa_min_offset = 0;
- cfa_max_offset = cfg->cfa_offset;
-
- min_offset = MIN (min_offset, cfa_min_offset);
- max_offset = MAX (max_offset, cfa_max_offset);
+
+ compute_frame_size (cfg);
/*
* The stack frame looks like this:
*/
if (cfg->verbose_level > 1)
- printf ("GC Map for %s: 0x%x-0x%x\n", mono_method_full_name (cfg->method, TRUE), min_offset, max_offset);
+ printf ("GC Map for %s: 0x%x-0x%x\n", mono_method_full_name (cfg->method, TRUE), gcfg->min_offset, gcfg->max_offset);
- nslots = (max_offset - min_offset) / sizeof (gpointer);
+ nslots = (gcfg->max_offset - gcfg->min_offset) / sizeof (gpointer);
/* slot [i] == type of slot at fp - <min_offset> + i*4/8 */
slots = g_new0 (StackSlotType, nslots);
live_intervals = g_new0 (GSList*, nslots);
gcfg->nslots = nslots;
gcfg->live_intervals = live_intervals;
gcfg->starts_pinned = starts_pinned;
- gcfg->min_offset = min_offset;
- gcfg->max_offset = max_offset;
/* All slots start out as PIN */
for (i = 0; i < nslots; ++i)
- slots [i] = SLOT_PIN;
-
- /* Slots for locals are NOREF by default */
- locals_min_slot = (locals_min_offset - min_offset) / sizeof (gpointer);
- locals_max_slot = (locals_max_offset - min_offset) / sizeof (gpointer);
- for (i = locals_min_slot; i < locals_max_slot; ++i)
- slots [i] = SLOT_NOREF;
+ set_slot (gcfg, i, SLOT_PIN);
+ process_spill_slots (cfg);
process_other_slots (cfg);
process_locals (cfg);
process_arguments (cfg);
-#if 1
- /* Debugging support */
- {
- static int precise_count;
-
- precise_count ++;
- if (getenv ("MONO_GCMAP_COUNT")) {
- if (precise_count == atoi (getenv ("MONO_GCMAP_COUNT")))
- printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
- if (precise_count > atoi (getenv ("MONO_GCMAP_COUNT"))) {
- for (i = 0; i < nslots; ++i)
- slots [i] = SLOT_PIN;
- }
- }
- }
-#endif
-
/* Create the GC Map */
has_ref_slots = FALSE;
gc_maps_size += alloc_size;
map->frame_reg = cfg->frame_reg;
- map->frame_offset = min_offset;
+ map->frame_offset = gcfg->min_offset;
map->nslots = nslots;
map->bitmap_width = bitmap_width;
map->has_ref_slots = has_ref_slots;