- break;
- }
-
- return code;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - peephole_pass */
-/* */
-/* Function - Form a peephole pass at the code looking for */
-/* simple optimizations. */
-/* */
-/*------------------------------------------------------------------*/
-
-static void
-peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- MonoInst *ins, *last_ins = NULL;
- ins = bb->code;
-
- while (ins) {
-
- switch (ins->opcode) {
- case OP_MUL_IMM:
- /* remove unnecessary multiplication with 1 */
- if (ins->inst_imm == 1) {
- if (ins->dreg != ins->sreg1) {
- ins->opcode = OP_MOVE;
- } else {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- }
- }
- break;
- case OP_LOAD_MEMBASE:
- case OP_LOADI4_MEMBASE:
- /*
- * OP_STORE_MEMBASE_REG reg, offset(basereg)
- * OP_LOAD_MEMBASE offset(basereg), reg
- */
- if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
- || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
- ins->inst_basereg == last_ins->inst_destbasereg &&
- ins->inst_offset == last_ins->inst_offset) {
- if (ins->dreg == last_ins->sreg1) {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- } else {
- //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
- ins->opcode = OP_MOVE;
- ins->sreg1 = last_ins->sreg1;
- }
-
- /*
- * Note: reg1 must be different from the basereg in the second load
- * OP_LOAD_MEMBASE offset(basereg), reg1
- * OP_LOAD_MEMBASE offset(basereg), reg2
- * -->
- * OP_LOAD_MEMBASE offset(basereg), reg1
- * OP_MOVE reg1, reg2
- */
- } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
- || last_ins->opcode == OP_LOAD_MEMBASE) &&
- ins->inst_basereg != last_ins->dreg &&
- ins->inst_basereg == last_ins->inst_basereg &&
- ins->inst_offset == last_ins->inst_offset) {
-
- if (ins->dreg == last_ins->dreg) {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- } else {
- ins->opcode = OP_MOVE;
- ins->sreg1 = last_ins->dreg;
- }
-
- //g_assert_not_reached ();
-
-#if 0
- /*
- * OP_STORE_MEMBASE_IMM imm, offset(basereg)
- * OP_LOAD_MEMBASE offset(basereg), reg
- * -->
- * OP_STORE_MEMBASE_IMM imm, offset(basereg)
- * OP_ICONST reg, imm
- */
- } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
- || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
- ins->inst_basereg == last_ins->inst_destbasereg &&
- ins->inst_offset == last_ins->inst_offset) {
- //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
- ins->opcode = OP_ICONST;
- ins->inst_c0 = last_ins->inst_imm;
- g_assert_not_reached (); // check this rule
-#endif
- }
- break;
- case OP_LOADU1_MEMBASE:
- case OP_LOADI1_MEMBASE:
- if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
- ins->inst_basereg == last_ins->inst_destbasereg &&
- ins->inst_offset == last_ins->inst_offset) {
- if (ins->dreg == last_ins->sreg1) {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- } else {
- //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
- ins->opcode = OP_MOVE;
- ins->sreg1 = last_ins->sreg1;
- }
- }
- break;
- case OP_LOADU2_MEMBASE:
- case OP_LOADI2_MEMBASE:
- if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
- ins->inst_basereg == last_ins->inst_destbasereg &&
- ins->inst_offset == last_ins->inst_offset) {
- if (ins->dreg == last_ins->sreg1) {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- } else {
- ins->opcode = OP_MOVE;
- ins->sreg1 = last_ins->sreg1;
- }
- }
- break;
- case CEE_CONV_I4:
- case CEE_CONV_U4:
- case OP_MOVE:
- /*
- * OP_MOVE reg, reg
- */
- if (ins->dreg == ins->sreg1) {
- if (last_ins)
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- }
- /*
- * OP_MOVE sreg, dreg
- * OP_MOVE dreg, sreg
- */
- if (last_ins && last_ins->opcode == OP_MOVE &&
- ins->sreg1 == last_ins->dreg &&
- ins->dreg == last_ins->sreg1) {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- }
- break;
- }
- last_ins = ins;
- ins = ins->next;
- }
- bb->last_ins = last_ins;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - mono_spillvar_offset */
-/* */
-/* Function - Returns the offset used by spillvar. It allocates */
-/* a new spill variable if necessary. */
-/* */
-/*------------------------------------------------------------------*/
-
-static int
-mono_spillvar_offset (MonoCompile *cfg, int spillvar)
-{
- MonoSpillInfo **si, *info;
- int i = 0;
-
- si = &cfg->spill_info;
-
- while (i <= spillvar) {
-
- if (!*si) {
- *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
- info->next = NULL;
- info->offset = cfg->stack_offset;
- cfg->stack_offset += sizeof (gpointer);
- }
-
- if (i == spillvar)
- return (*si)->offset;
-
- i++;
- si = &(*si)->next;
- }
-
- g_assert_not_reached ();
- return 0;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - mono_spillvar_offset_float */
-/* */
-/* Function - */
-/* */
-/*------------------------------------------------------------------*/
-
-static int
-mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
-{
- MonoSpillInfo **si, *info;
- int i = 0;
-
- si = &cfg->spill_info_float;
-
- while (i <= spillvar) {
-
- if (!*si) {
- *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
- info->next = NULL;
- cfg->stack_offset = S390_ALIGN(cfg->stack_offset, S390_STACK_ALIGNMENT);
- info->offset = cfg->stack_offset;
- cfg->stack_offset += sizeof (double);
- }
-
- if (i == spillvar)
- return (*si)->offset;
-
- i++;
- si = &(*si)->next;
- }
-
- g_assert_not_reached ();
- return 0;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - print_ins */
-/* */
-/* Function - Decode and print the instruction for tracing. */
-/* */
-/*------------------------------------------------------------------*/
-
-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));
- if (spec [MONO_INST_DEST]) {
- if (ins->dreg >= MONO_MAX_IREGS)
- g_print (" R%d <-", ins->dreg);
- else
- g_print (" %s <-", mono_arch_regname (ins->dreg));
- }
- if (spec [MONO_INST_SRC1]) {
- if (ins->sreg1 >= MONO_MAX_IREGS)
- g_print (" R%d", ins->sreg1);
- else
- g_print (" %s", mono_arch_regname (ins->sreg1));
- }
- if (spec [MONO_INST_SRC2]) {
- if (ins->sreg2 >= MONO_MAX_IREGS)
- g_print (" R%d", ins->sreg2);
- else
- g_print (" %s", mono_arch_regname (ins->sreg2));
- }
- if (spec [MONO_INST_CLOB])
- g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
- g_print ("\n");
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - print_regtrack. */
-/* */
-/* Function - */
-/* */
-/*------------------------------------------------------------------*/
-
-static void
-print_regtrack (RegTrack *t, int num)
-{
- int i;
- char buf [32];
- const char *r;
-
- for (i = 0; i < num; ++i) {
- if (!t [i].born_in)
- continue;
- if (i >= MONO_MAX_IREGS) {
- g_snprintf (buf, sizeof(buf), "R%d", i);
- r = buf;
- } else
- r = mono_arch_regname (i);
- g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
- }
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - inst_list_prepend */
-/* */
-/* Function - Prepend an instruction to the list. */
-/* */
-/*------------------------------------------------------------------*/
-
-static inline InstList*
-inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
-{
- InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
- item->data = data;
- item->prev = NULL;
- item->next = list;
- if (list)
- list->prev = item;
- return item;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - get_register_force_spilling */
-/* */
-/* Function - Force the spilling of the variable in the */
-/* symbolic register 'reg'. */
-/* */
-/*------------------------------------------------------------------*/
-
-static int
-get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
-{
- MonoInst *load;
- int i, sel, spill;
-
- sel = cfg->rs->iassign [reg];
- i = reg;
- spill = ++cfg->spill_count;
- cfg->rs->iassign [i] = -spill - 1;
- mono_regstate_free_int (cfg->rs, sel);
- /*----------------------------------------------------------*/
- /* we need to create a spill var and insert a load to sel */
- /* after the current instruction */
- /*----------------------------------------------------------*/
- MONO_INST_NEW (cfg, load, OP_LOAD_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%08x(%%sp)) R%d (freed %s)\n",
- spill, load->inst_offset, i, mono_arch_regname (sel)));
- i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
- g_assert (i == sel);
-
- return sel;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - get_register_spilling */
-/* */
-/* Function - */
-/* */
-/*------------------------------------------------------------------*/
-
-static int
-get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
-{
- MonoInst *load;
- int i, sel, spill;
-
- DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
- /* exclude the registers in the current instruction */
- if (reg != ins->sreg1 &&
- (reg_is_freeable (ins->sreg1) ||
- (ins->sreg1 >= MONO_MAX_IREGS &&
- cfg->rs->iassign [ins->sreg1] >= 0))) {
- if (ins->sreg1 >= MONO_MAX_IREGS)
- regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
- else
- regmask &= ~ (1 << ins->sreg1);
- DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
- }
- if (reg != ins->sreg2 &&
- (reg_is_freeable (ins->sreg2) ||
- (ins->sreg2 >= MONO_MAX_IREGS &&
- cfg->rs->iassign [ins->sreg2] >= 0))) {
- if (ins->sreg2 >= MONO_MAX_IREGS)
- regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
- else
- regmask &= ~ (1 << ins->sreg2);
- DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
- }
- if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
- regmask &= ~ (1 << ins->dreg);
- DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
- }
-
- DEBUG (g_print ("available regmask: 0x%08x\n", 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_IREGS; ++i) {
- if (regmask & (1 << i)) {
- sel = i;
- DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
- break;
- }
- }
- i = cfg->rs->isymbolic [sel];
- spill = ++cfg->spill_count;
- cfg->rs->iassign [i] = -spill - 1;
- mono_regstate_free_int (cfg->rs, sel);
- /* we need to create a spill var and insert a load to sel after the current instruction */
- MONO_INST_NEW (cfg, load, OP_LOAD_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%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
- i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
- g_assert (i == sel);
-
- return sel;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - get_float_register_spilling */
-/* */
-/* Function - */
-/* */
-/*------------------------------------------------------------------*/
-
-static int
-get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
-{
- MonoInst *load;
- int i, sel, spill;
-
- DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
- /* exclude the registers in the current instruction */
- if (reg != ins->sreg1 &&
- (freg_is_freeable (ins->sreg1) ||
- (ins->sreg1 >= MONO_MAX_FREGS &&
- cfg->rs->fassign [ins->sreg1] >= 0))) {
- if (ins->sreg1 >= MONO_MAX_FREGS)
- regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
- else
- regmask &= ~ (1 << ins->sreg1);
- DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
- }
- if (reg != ins->sreg2 &&
- (freg_is_freeable (ins->sreg2) ||
- (ins->sreg2 >= MONO_MAX_FREGS &&
- cfg->rs->fassign [ins->sreg2] >= 0))) {
- if (ins->sreg2 >= MONO_MAX_FREGS)
- regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
- else
- regmask &= ~ (1 << ins->sreg2);
- DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
- }
- if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
- regmask &= ~ (1 << ins->dreg);
- DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
- }
-
- DEBUG (g_print ("available regmask: 0x%08x\n", 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 & (1 << i)) {
- sel = i;
- DEBUG (g_print ("selected register %s has assignment %d\n",
- mono_arch_regname (sel), cfg->rs->fassign [sel]));
- break;
- }
- }
- i = cfg->rs->fsymbolic [sel];
- spill = ++cfg->spill_count;
- cfg->rs->fassign [i] = -spill - 1;
- mono_regstate_free_float(cfg->rs, sel);
- /* we need to create a spill var and insert a load to sel after the current instruction */
- MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
- load->dreg = sel;
- load->inst_basereg = cfg->frame_reg;
- load->inst_offset = mono_spillvar_offset_float (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%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
- i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
- g_assert (i == sel);
-
- return sel;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - create_copy_ins */
-/* */
-/* Function - Create an instruction to copy from reg to reg. */
-/* */
-/*------------------------------------------------------------------*/
-
-static MonoInst*
-create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
-{
- MonoInst *copy;
- MONO_INST_NEW (cfg, copy, OP_MOVE);
- copy->dreg = dest;
- copy->sreg1 = src;
- if (ins) {
- copy->next = ins->next;
- ins->next = copy;
- }
- DEBUG (g_print ("\tforced copy from %s to %s\n",
- mono_arch_regname (src), mono_arch_regname (dest)));
- return copy;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - create_copy_ins_float */
-/* */
-/* Function - Create an instruction to copy from float reg to */
-/* float reg. */
-/* */
-/*------------------------------------------------------------------*/
-
-static MonoInst*
-create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
-{
- MonoInst *copy;
- MONO_INST_NEW (cfg, copy, OP_FMOVE);
- copy->dreg = dest;
- copy->sreg1 = src;
- if (ins) {
- copy->next = ins->next;
- ins->next = copy;
- }
- DEBUG (g_print ("\tforced copy from %s to %s\n",
- mono_arch_regname (src), mono_arch_regname (dest)));
- return copy;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - create_spilled_store */
-/* */
-/* Function - Spill register to storage. */
-/* */
-/*------------------------------------------------------------------*/
-
-static MonoInst*
-create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
-{
- MonoInst *store;
- MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
- store->sreg1 = reg;
- store->inst_destbasereg = cfg->frame_reg;
- store->inst_offset = mono_spillvar_offset (cfg, spill);
- if (ins) {
- store->next = ins->next;
- ins->next = store;