- /*
- * 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_X86_FP_NEEDS_LOAD_SPILL = 1 << 0,
- MONO_X86_FP_NEEDS_SPILL = 1 << 1,
- MONO_X86_FP_NEEDS_LOAD = 1 << 2,
- MONO_X86_REG_NOT_ECX = 1 << 3,
- MONO_X86_REG_EAX = 1 << 4,
- MONO_X86_REG_EDX = 1 << 5,
- MONO_X86_REG_ECX = 1 << 6
-};
-
-static int
-mono_amd64_alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, guint32 dest_mask, int sym_reg, int flags)
-{
- int val;
- int test_mask = dest_mask;
-
- if (flags & MONO_X86_REG_EAX)
- test_mask &= (1 << AMD64_RAX);
- else if (flags & MONO_X86_REG_EDX)
- test_mask &= (1 << AMD64_RDX);
- else if (flags & MONO_X86_REG_ECX)
- test_mask &= (1 << AMD64_RCX);
- else if (flags & MONO_X86_REG_NOT_ECX)
- test_mask &= ~ (1 << AMD64_RCX);
-
- val = mono_regstate_alloc_int (cfg->rs, test_mask);
- if (val >= 0 && test_mask != dest_mask)
- DEBUG(g_print ("\tUsed flag to allocate reg %s for R%u\n", mono_arch_regname (val), sym_reg));
-
- if (val < 0 && (flags & MONO_X86_REG_NOT_ECX)) {
- DEBUG(g_print ("\tFailed to allocate flag suggested mask (%u) but exluding ECX\n", test_mask));
- val = mono_regstate_alloc_int (cfg->rs, (dest_mask & (~1 << AMD64_RCX)));
- }
-
- if (val < 0) {
- val = mono_regstate_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
-mono_amd64_alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, guint32 dest_mask, int sym_reg)
-{
- int val;
-
- val = mono_regstate_alloc_float (cfg->rs, dest_mask);
-
- if (val < 0) {
- val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
- }
-
- return val;
-}
-
-static inline void
-assign_ireg (MonoRegState *rs, int reg, int hreg)
-{
- g_assert (reg >= MONO_MAX_IREGS);
- g_assert (hreg < MONO_MAX_IREGS);
- g_assert (! is_global_ireg (hreg));
-
- rs->iassign [reg] = hreg;
- rs->isymbolic [hreg] = reg;
- rs->ifree_mask &= ~ (1 << hreg);
-}
-
-/*#include "cprop.c"*/
-
-/*
- * Local register allocation.
- * We first scan the list of instructions and we save the liveness info of
- * each register (when the register is first used, when it's value is set etc.).
- * We also reverse the list of instructions (in the InstList list) because assigning
- * registers backwards allows for more tricks to be used.
- */
-void
-mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- MonoInst *ins;
- MonoRegState *rs = cfg->rs;
- int i, val, fpcount;
- RegTrack *reginfo, *reginfof;
- RegTrack *reginfo1, *reginfo2, *reginfod;
- InstList *tmp, *reversed = NULL;
- const char *spec;
- guint32 src1_mask, src2_mask, dest_mask;
- GList *fspill_list = NULL;
- int fspill = 0;
-
- 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);
- rs->ifree_mask = AMD64_CALLEE_REGS;
- rs->ffree_mask = AMD64_CALLEE_FREGS;
-
- if (!use_sse2)
- /* The fp stack is 6 entries deep */
- rs->ffree_mask = 0x3f;
-
- ins = bb->code;
-
- /*if (cfg->opt & MONO_OPT_COPYPROP)
- local_copy_prop (cfg, ins);*/
-
- i = 1;
- fpcount = 0;
- DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
- /* forward pass on the instructions to collect register liveness info */
- while (ins) {
- spec = ins_spec [ins->opcode];
-
- DEBUG (print_ins (i, ins));
-
- if (spec [MONO_INST_SRC1]) {
- if (spec [MONO_INST_SRC1] == 'f') {
- reginfo1 = reginfof;
-
- if (!use_sse2) {
- GList *spill;
-
- spill = g_list_first (fspill_list);
- if (spill && fpcount < FPSTACK_SIZE) {
- reginfo1 [ins->sreg1].flags |= MONO_X86_FP_NEEDS_LOAD;
- fspill_list = g_list_remove (fspill_list, spill->data);
- } else
- fpcount--;
- }
- }
- else
- reginfo1 = reginfo;
- reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
- reginfo1 [ins->sreg1].last_use = i;
- if (spec [MONO_INST_SRC1] == 'L') {
- /* 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;
- if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
- reginfo1 [ins->sreg1 + 1].born_in = i;
-
- reginfo1 [ins->sreg1].flags |= MONO_X86_REG_EAX;
- reginfo1 [ins->sreg1 + 1].flags |= MONO_X86_REG_EDX;
- }
- } else {
- ins->sreg1 = -1;
- }
- if (spec [MONO_INST_SRC2]) {
- if (spec [MONO_INST_SRC2] == 'f') {
- reginfo2 = reginfof;
-
- if (!use_sse2) {
- GList *spill;
-
- spill = g_list_first (fspill_list);
- if (spill) {
- reginfo2 [ins->sreg2].flags |= MONO_X86_FP_NEEDS_LOAD;
- fspill_list = g_list_remove (fspill_list, spill->data);
- if (fpcount >= FPSTACK_SIZE) {
- fspill++;
- fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
- reginfo2 [ins->sreg2].flags |= MONO_X86_FP_NEEDS_LOAD_SPILL;
- }
- } else
- fpcount--;
- }
- }
- else
- reginfo2 = reginfo;
- reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
- reginfo2 [ins->sreg2].last_use = i;
- if (spec [MONO_INST_SRC2] == 'L') {
- /* 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;
- 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_CLOB] == 's') {
- reginfo2 [ins->sreg1].flags |= MONO_X86_REG_NOT_ECX;
- reginfo2 [ins->sreg2].flags |= MONO_X86_REG_ECX;
- }
- } else {
- ins->sreg2 = -1;
- }
- if (spec [MONO_INST_DEST]) {
- if (spec [MONO_INST_DEST] == 'f') {
- reginfod = reginfof;
- if (!use_sse2 && (spec [MONO_INST_CLOB] != 'm')) {
- if (fpcount >= FPSTACK_SIZE) {
- reginfod [ins->dreg].flags |= MONO_X86_FP_NEEDS_SPILL;
- fspill++;
- fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
- fpcount--;
- }
- fpcount++;
- }
- }
- 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;
- if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
- reginfod [ins->dreg].born_in = i;
- if (spec [MONO_INST_DEST] == 'l' || spec [MONO_INST_DEST] == 'L') {
- /* 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;
- if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
- reginfod [ins->dreg + 1].born_in = i;
-
- reginfod [ins->dreg].flags |= MONO_X86_REG_EAX;
- reginfod [ins->dreg + 1].flags |= MONO_X86_REG_EDX;
- }
- } else {
- ins->dreg = -1;
- }
-
- if (spec [MONO_INST_CLOB] == 'c') {
- /* A call instruction implicitly uses all registers in call->out_ireg_args */
-
- MonoCallInst *call = (MonoCallInst*)ins;
- GSList *list;
-
- list = call->out_ireg_args;
- if (list) {
- while (list) {
- guint64 regpair;
- int reg, hreg;
-
- regpair = (guint64) (list->data);
- hreg = regpair >> 32;
- reg = regpair & 0xffffffff;
-
- reginfo [reg].prev_use = reginfo [reg].last_use;
- reginfo [reg].last_use = i;
-
- list = g_slist_next (list);
- }
- }
-
- list = call->out_freg_args;
- if (use_sse2 && list) {
- while (list) {
- guint64 regpair;
- int reg, hreg;
-
- regpair = (guint64) (list->data);
- hreg = regpair >> 32;
- reg = regpair & 0xffffffff;
-
- 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);
- ++i;
- ins = ins->next;
- }
-
- // todo: check if we have anything left on fp stack, in verify mode?
- fspill = 0;
-
- DEBUG (print_regtrack (reginfo, rs->next_vireg));
- DEBUG (print_regtrack (reginfof, rs->next_vfreg));
- tmp = reversed;
- while (tmp) {
- int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
- dest_mask = src1_mask = src2_mask = AMD64_CALLEE_REGS;
- --i;
- ins = tmp->data;
- spec = ins_spec [ins->opcode];
- prev_dreg = -1;
- clob_dreg = -1;
- DEBUG (g_print ("processing:"));
- DEBUG (print_ins (i, ins));
- if (spec [MONO_INST_CLOB] == 's') {
- /*
- * Shift opcodes, SREG2 must be RCX
- */
- if (rs->ifree_mask & (1 << AMD64_RCX)) {
- if (ins->sreg2 < MONO_MAX_IREGS) {
- /* Argument already in hard reg, need to copy */
- MonoInst *copy = create_copy_ins (cfg, AMD64_RCX, ins->sreg2, NULL, FALSE);
- insert_before_ins (ins, tmp, copy);
- }
- else {
- DEBUG (g_print ("\tshortcut assignment of R%d to ECX\n", ins->sreg2));
- assign_ireg (rs, ins->sreg2, AMD64_RCX);
- }
- } else {
- int need_ecx_spill = TRUE;
- /*
- * we first check if src1/dreg is already assigned a register
- * and then we force a spill of the var assigned to ECX.
- */
- /* the destination register can't be ECX */
- dest_mask &= ~ (1 << AMD64_RCX);
- src1_mask &= ~ (1 << AMD64_RCX);
- val = rs->iassign [ins->dreg];
- /*
- * the destination register is already assigned to ECX:
- * we need to allocate another register for it and then
- * copy from this to ECX.
- */
- if (val == AMD64_RCX && ins->dreg != ins->sreg2) {
- int new_dest;
- new_dest = mono_amd64_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->dreg, reginfo [ins->dreg].flags);
- g_assert (new_dest >= 0);
- DEBUG (g_print ("\tclob:s changing dreg R%d to %s from ECX\n", ins->dreg, mono_arch_regname (new_dest)));
-
- rs->isymbolic [new_dest] = ins->dreg;
- rs->iassign [ins->dreg] = new_dest;
- clob_dreg = ins->dreg;
- ins->dreg = new_dest;
- create_copy_ins (cfg, AMD64_RCX, new_dest, ins, FALSE);
- need_ecx_spill = FALSE;
- /*DEBUG (g_print ("\tforced spill of R%d\n", ins->dreg));
- val = get_register_force_spilling (cfg, tmp, ins, ins->dreg);
- rs->iassign [ins->dreg] = val;
- rs->isymbolic [val] = prev_dreg;
- ins->dreg = val;*/
- }
- if (is_global_ireg (ins->sreg2)) {
- MonoInst *copy = create_copy_ins (cfg, AMD64_RCX, ins->sreg2, NULL, FALSE);
- insert_before_ins (ins, tmp, copy);
- }
- else {
- val = rs->iassign [ins->sreg2];
- if (val >= 0 && val != AMD64_RCX) {
- MonoInst *move = create_copy_ins (cfg, AMD64_RCX, val, NULL, FALSE);
- DEBUG (g_print ("\tmoved arg from R%d (%d) to ECX\n", val, ins->sreg2));
- move->next = ins;
- g_assert_not_reached ();
- /* FIXME: where is move connected to the instruction list? */
- //tmp->prev->data->next = move;
- }
- else {
- if (val == AMD64_RCX)
- need_ecx_spill = FALSE;
- }
- }
- if (need_ecx_spill && !(rs->ifree_mask & (1 << AMD64_RCX))) {
- DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [AMD64_RCX]));
- get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [AMD64_RCX], FALSE);
- mono_regstate_free_int (rs, AMD64_RCX);
- }
- if (!is_global_ireg (ins->sreg2))
- /* force-set sreg2 */
- assign_ireg (rs, ins->sreg2, AMD64_RCX);
- }
- ins->sreg2 = AMD64_RCX;
- } else if (spec [MONO_INST_CLOB] == 'd') {
- /*
- * DIVISION/REMAINER
- */
- int dest_reg = AMD64_RAX;
- int clob_reg = AMD64_RDX;
- if (spec [MONO_INST_DEST] == 'd') {
- dest_reg = AMD64_RDX; /* reminder */
- clob_reg = AMD64_RAX;
- }
- if (is_global_ireg (ins->dreg))
- val = ins->dreg;
- else
- val = rs->iassign [ins->dreg];
- if (0 && val >= 0 && val != dest_reg && !(rs->ifree_mask & (1 << dest_reg))) {
- DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_reg]));
- get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_reg], FALSE);
- mono_regstate_free_int (rs, dest_reg);
- }
- if (val < 0) {
- if (val < -1) {
- /* the register gets spilled after this inst */
- int spill = -val -1;
- dest_mask = 1 << clob_reg;
- prev_dreg = ins->dreg;
- val = mono_regstate_alloc_int (rs, dest_mask);
- if (val < 0)
- val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg, FALSE);
- rs->iassign [ins->dreg] = val;
- if (spill)
- create_spilled_store (cfg, spill, val, prev_dreg, ins, FALSE);
- DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
- rs->isymbolic [val] = prev_dreg;
- ins->dreg = val;
- } else {
- DEBUG (g_print ("\tshortcut assignment of R%d to %s\n", ins->dreg, mono_arch_regname (dest_reg)));
- prev_dreg = ins->dreg;
- assign_ireg (rs, ins->dreg, dest_reg);
- ins->dreg = dest_reg;
- val = dest_reg;
- }
- }
-
- //DEBUG (g_print ("dest reg in div assigned: %s\n", mono_arch_regname (val)));
- if (val != dest_reg) { /* force a copy */
- create_copy_ins (cfg, val, dest_reg, ins, FALSE);
- if (!(rs->ifree_mask & (1 << dest_reg)) && rs->isymbolic [dest_reg] >= MONO_MAX_IREGS) {
- DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_reg]));
- get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_reg], FALSE);
- mono_regstate_free_int (rs, dest_reg);
- }
- }
- if (!(rs->ifree_mask & (1 << clob_reg)) && (clob_reg != val) && (rs->isymbolic [clob_reg] >= MONO_MAX_IREGS)) {
- DEBUG (g_print ("\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);
- }
- src1_mask = 1 << AMD64_RAX;
- src2_mask = 1 << AMD64_RCX;
- }
- if (spec [MONO_INST_DEST] == 'l') {
- int hreg;
- val = rs->iassign [ins->dreg];
- /* check special case when dreg have been moved from ecx (clob shift) */
- if (spec [MONO_INST_CLOB] == 's' && clob_dreg != -1)
- hreg = clob_dreg + 1;
- else
- hreg = ins->dreg + 1;
-
- /* base prev_dreg on fixed hreg, handle clob case */
- val = hreg - 1;
-
- if (val != rs->isymbolic [AMD64_RAX] && !(rs->ifree_mask & (1 << AMD64_RAX))) {
- DEBUG (g_print ("\t(long-low) forced spill of R%d\n", rs->isymbolic [AMD64_RAX]));
- get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [AMD64_RAX], FALSE);
- mono_regstate_free_int (rs, AMD64_RAX);
- }
- if (hreg != rs->isymbolic [AMD64_RDX] && !(rs->ifree_mask & (1 << AMD64_RDX))) {
- DEBUG (g_print ("\t(long-high) forced spill of R%d\n", rs->isymbolic [AMD64_RDX]));
- get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [AMD64_RDX], FALSE);
- mono_regstate_free_int (rs, AMD64_RDX);
- }
- }
-
- /*
- * TRACK DREG
- */
- if (spec [MONO_INST_DEST] == 'f') {
- if (use_sse2) {
- /* Allocate an XMM reg the same way as an int reg */
- if (reg_is_soft (ins->dreg, TRUE)) {
- val = rs->fassign [ins->dreg];
- prev_dreg = ins->dreg;
-
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- val = mono_amd64_alloc_float_reg (cfg, tmp, ins, AMD64_CALLEE_FREGS, ins->dreg);
- rs->fassign [ins->dreg] = val;
- if (spill)
- create_spilled_store (cfg, spill, val, prev_dreg, ins, TRUE);
- }
- DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_amd64_regname (val, TRUE), ins->dreg));
- rs->fsymbolic [val] = prev_dreg;
- ins->dreg = val;
- }
- }
- else if (spec [MONO_INST_CLOB] != 'm') {
- if (reginfof [ins->dreg].flags & MONO_X86_FP_NEEDS_SPILL) {
- GList *spill_node;
- MonoInst *store;
- spill_node = g_list_first (fspill_list);
- g_assert (spill_node);
-
- store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
- insert_before_ins (ins, tmp, store);
- fspill_list = g_list_remove (fspill_list, spill_node->data);
- fspill--;
- }
- }
- } else if (spec [MONO_INST_DEST] == 'L') {
- int hreg;
- val = rs->iassign [ins->dreg];
- /* check special case when dreg have been moved from ecx (clob shift) */
- if (spec [MONO_INST_CLOB] == 's' && clob_dreg != -1)
- hreg = clob_dreg + 1;
- else
- hreg = ins->dreg + 1;
-
- /* base prev_dreg on fixed hreg, handle clob case */
- prev_dreg = hreg - 1;
-
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- val = mono_amd64_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->dreg, reginfo [ins->dreg].flags);
- rs->iassign [ins->dreg] = val;
- if (spill)
- create_spilled_store (cfg, spill, val, prev_dreg, ins, FALSE);
- }
-
- DEBUG (g_print ("\tassigned dreg (long) %s to dest R%d\n", mono_arch_regname (val), hreg - 1));
-
- rs->isymbolic [val] = hreg - 1;
- ins->dreg = val;
-
- val = rs->iassign [hreg];
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- val = mono_amd64_alloc_int_reg (cfg, tmp, ins, dest_mask, hreg, reginfo [hreg].flags);
- rs->iassign [hreg] = val;
- if (spill)
- create_spilled_store (cfg, spill, val, hreg, ins, FALSE);
- }
-
- DEBUG (g_print ("\tassigned hreg (long-high) %s to dest R%d\n", mono_arch_regname (val), hreg));
- rs->isymbolic [val] = hreg;
- /* save reg allocating into unused */
- ins->unused = val;
-
- /* check if we can free our long reg */
- if (reg_is_freeable (val, FALSE) && hreg >= 0 && reginfo [hreg].born_in >= i) {
- DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (val), hreg, reginfo [hreg].born_in));
- mono_regstate_free_int (rs, val);
- }
- }
- else if (ins->dreg >= MONO_MAX_IREGS) {
- int hreg;
- val = rs->iassign [ins->dreg];
- if (spec [MONO_INST_DEST] == 'l') {
- /* check special case when dreg have been moved from ecx (clob shift) */
- if (spec [MONO_INST_CLOB] == 's' && clob_dreg != -1)
- hreg = clob_dreg + 1;
- else
- hreg = ins->dreg + 1;
-
- /* base prev_dreg on fixed hreg, handle clob case */
- prev_dreg = hreg - 1;
- } else
- prev_dreg = ins->dreg;
-
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- val = mono_amd64_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->dreg, reginfo [ins->dreg].flags);
- rs->iassign [ins->dreg] = val;
- if (spill)
- create_spilled_store (cfg, spill, val, prev_dreg, ins, FALSE);
- }
- DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
- rs->isymbolic [val] = prev_dreg;
- ins->dreg = val;
- /* handle cases where lreg needs to be eax:edx */
- if (spec [MONO_INST_DEST] == 'l') {
- /* check special case when dreg have been moved from ecx (clob shift) */
- int hreg = prev_dreg + 1;
- val = rs->iassign [hreg];
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- val = mono_amd64_alloc_int_reg (cfg, tmp, ins, dest_mask, hreg, reginfo [hreg].flags);
- rs->iassign [hreg] = val;
- if (spill)
- create_spilled_store (cfg, spill, val, hreg, ins, FALSE);
- }
- DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
- rs->isymbolic [val] = hreg;
- if (ins->dreg == AMD64_RAX) {
- if (val != AMD64_RDX)
- create_copy_ins (cfg, val, AMD64_RDX, ins, FALSE);
- } else if (ins->dreg == AMD64_RDX) {
- if (val == AMD64_RAX) {
- /* swap */
- g_assert_not_reached ();
- } else {
- /* two forced copies */
- create_copy_ins (cfg, val, AMD64_RDX, ins, FALSE);
- create_copy_ins (cfg, ins->dreg, AMD64_RAX, ins, FALSE);
- }
- } else {
- if (val == AMD64_RDX) {
- create_copy_ins (cfg, ins->dreg, AMD64_RAX, ins, FALSE);
- } else {
- /* two forced copies */
- create_copy_ins (cfg, val, AMD64_RDX, ins, FALSE);
- create_copy_ins (cfg, ins->dreg, AMD64_RAX, ins, FALSE);
- }
- }
- if (reg_is_freeable (val, FALSE) && hreg >= 0 && reginfo [hreg].born_in >= i) {
- DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
- mono_regstate_free_int (rs, val);
- }
- } else if (spec [MONO_INST_DEST] == 'a' && ins->dreg != AMD64_RAX && spec [MONO_INST_CLOB] != 'd') {
- /* this instruction only outputs to EAX, need to copy */
- create_copy_ins (cfg, ins->dreg, AMD64_RAX, ins, FALSE);
- } else if (spec [MONO_INST_DEST] == 'd' && ins->dreg != AMD64_RDX && spec [MONO_INST_CLOB] != 'd') {
- create_copy_ins (cfg, ins->dreg, AMD64_RDX, ins, FALSE);
- }
- }
-
- if (use_sse2 && spec [MONO_INST_DEST] == 'f' && reg_is_freeable (ins->dreg, TRUE) && prev_dreg >= 0 && reginfof [prev_dreg].born_in >= i) {
- DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_fregname (ins->dreg), prev_dreg, reginfof [prev_dreg].born_in));
- mono_regstate_free_float (rs, ins->dreg);
- }
- if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg, FALSE) && prev_dreg >= 0 && reginfo [prev_dreg].born_in >= i) {
- DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
- mono_regstate_free_int (rs, ins->dreg);
- }
-
- /* put src1 in EAX if it needs to be */
- if (spec [MONO_INST_SRC1] == 'a') {
- if (!(rs->ifree_mask & (1 << AMD64_RAX))) {
- DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [AMD64_RAX]));
- get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [AMD64_RAX], FALSE);
- mono_regstate_free_int (rs, AMD64_RAX);
- }
- if (ins->sreg1 < MONO_MAX_IREGS) {
- /* The argument is already in a hard reg, need to copy */
- MonoInst *copy = create_copy_ins (cfg, AMD64_RAX, ins->sreg1, NULL, FALSE);
- insert_before_ins (ins, tmp, copy);
- }
- else
- /* force-set sreg1 */
- assign_ireg (rs, ins->sreg1, AMD64_RAX);
- ins->sreg1 = AMD64_RAX;
- }
-
- /*
- * TRACK SREG1
- */
- if (spec [MONO_INST_SRC1] == 'f') {
- if (use_sse2) {
- if (reg_is_soft (ins->sreg1, TRUE)) {
- val = rs->fassign [ins->sreg1];
- prev_sreg1 = ins->sreg1;
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- val = mono_amd64_alloc_float_reg (cfg, tmp, ins, AMD64_CALLEE_FREGS, ins->sreg1);
- rs->fassign [ins->sreg1] = val;
- DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_fregname (val), ins->sreg1));
- if (spill) {
- MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, TRUE);
- insert_before_ins (ins, tmp, store);
- }
- }
- rs->fsymbolic [val] = prev_sreg1;
- ins->sreg1 = val;
- } else {
- prev_sreg1 = -1;
- }
- }
- else
- if (reginfof [ins->sreg1].flags & MONO_X86_FP_NEEDS_LOAD) {
- MonoInst *load;
- MonoInst *store = NULL;
-
- if (reginfof [ins->sreg1].flags & MONO_X86_FP_NEEDS_LOAD_SPILL) {
- GList *spill_node;
- spill_node = g_list_first (fspill_list);
- g_assert (spill_node);
-
- store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);
- fspill_list = g_list_remove (fspill_list, spill_node->data);
- }
-
- fspill++;
- fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
- load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
- insert_before_ins (ins, tmp, load);
- if (store)
- insert_before_ins (load, tmp, store);
- }
- } else if ((spec [MONO_INST_DEST] == 'L') && (spec [MONO_INST_SRC1] == 'L')) {
- /* force source to be same as dest */
- rs->iassign [ins->sreg1] = ins->dreg;
- rs->iassign [ins->sreg1 + 1] = ins->unused;
-
- DEBUG (g_print ("\tassigned sreg1 (long) %s to sreg1 R%d\n", mono_arch_regname (ins->dreg), ins->sreg1));
- DEBUG (g_print ("\tassigned sreg1 (long-high) %s to sreg1 R%d\n", mono_arch_regname (ins->unused), ins->sreg1 + 1));
-
- ins->sreg1 = ins->dreg;
- /*
- * No need for saving the reg, we know that src1=dest in this cases
- * ins->inst_c0 = ins->unused;
- */
-
- /* make sure that we remove them from free mask */
- rs->ifree_mask &= ~ (1 << ins->dreg);
- rs->ifree_mask &= ~ (1 << ins->unused);
- }
- else if (ins->sreg1 >= MONO_MAX_IREGS) {
- val = rs->iassign [ins->sreg1];
- prev_sreg1 = ins->sreg1;
- if (val < 0) {
- int spill = 0;
- if (val < -1) {
- /* the register gets spilled after this inst */
- spill = -val -1;
- }
- if (0 && (ins->opcode == OP_MOVE)) {
- /*
- * small optimization: the dest register is already allocated
- * but the src one is not: we can simply assign the same register
- * here and peephole will get rid of the instruction later.
- * This optimization may interfere with the clobbering handling:
- * it removes a mov operation that will be added again to handle clobbering.
- * There are also some other issues that should with make testjit.
- */
- mono_regstate_alloc_int (rs, 1 << ins->dreg);
- val = rs->iassign [ins->sreg1] = ins->dreg;
- //g_assert (val >= 0);
- DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
- } else {
- //g_assert (val == -1); /* source cannot be spilled */
- val = mono_amd64_alloc_int_reg (cfg, tmp, ins, src1_mask, ins->sreg1, reginfo [ins->sreg1].flags);
- rs->iassign [ins->sreg1] = val;
- DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
- }
- if (spill) {
- MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL, FALSE);
- insert_before_ins (ins, tmp, store);
- }
- }
- rs->isymbolic [val] = prev_sreg1;
- ins->sreg1 = val;
- } else {
- prev_sreg1 = -1;
- }
-
- /* handle clobbering of sreg1 */
- if (((spec [MONO_INST_DEST] == 'f' && spec [MONO_INST_SRC1] == 'f' && use_sse2) || spec [MONO_INST_CLOB] == '1' || spec [MONO_INST_CLOB] == 's') && ins->dreg != ins->sreg1) {
- MonoInst *sreg2_copy = NULL;
- MonoInst *copy;
- gboolean fp = (spec [MONO_INST_SRC1] == 'f');
-
- if (ins->dreg == ins->sreg2) {
- /*
- * copying sreg1 to dreg could clobber sreg2, so allocate a new
- * register for it.
- */
- int reg2 = 0;
-
- if (fp)
- reg2 = mono_amd64_alloc_float_reg (cfg, tmp, ins, AMD64_CALLEE_FREGS, ins->sreg2);
- else
- reg2 = mono_amd64_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->sreg2, 0);
-
- DEBUG (g_print ("\tneed to copy sreg2 %s to reg %s\n", mono_amd64_regname (ins->sreg2, fp), mono_amd64_regname (reg2, fp)));
- sreg2_copy = create_copy_ins (cfg, reg2, ins->sreg2, NULL, fp);
- prev_sreg2 = ins->sreg2 = reg2;
-
- if (fp)
- mono_regstate_free_float (rs, reg2);
- else
- mono_regstate_free_int (rs, reg2);
- }