X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-ppc.c;h=159b77bbc663ac1a9fe0c41ef2bc8c7d418e399e;hb=31d03d041acc13818cdd392bc99890d1c524be34;hp=780a671115f83be4fb0c9f891853fd13486f5280;hpb=294754329498266d70371897763ca36a192193f2;p=mono.git diff --git a/mono/mini/mini-ppc.c b/mono/mini/mini-ppc.c index 780a671115f..159b77bbc66 100644 --- a/mono/mini/mini-ppc.c +++ b/mono/mini/mini-ppc.c @@ -17,6 +17,11 @@ #include "inssel.h" #include "cpu-g4.h" #include "trace.h" +#ifdef __APPLE__ +#include +#endif + +#define FORCE_INDIR_CALL 1 enum { TLS_MODE_DETECT, @@ -76,14 +81,30 @@ offsets_from_pthread_key (guint32 key, int *offset2) const char* mono_arch_regname (int reg) { - static const char * rnames[] = { - "ppc_r0", "ppc_sp", "ppc_r2", "ppc_r3", "ppc_r4", - "ppc_r5", "ppc_r6", "ppc_r7", "ppc_r8", "ppc_r9", - "ppc_r10", "ppc_r11", "ppc_r12", "ppc_r13", "ppc_r14", - "ppc_r15", "ppc_r16", "ppc_r17", "ppc_r18", "ppc_r19", - "ppc_r20", "ppc_r21", "ppc_r22", "ppc_r23", "ppc_r24", - "ppc_r25", "ppc_r26", "ppc_r27", "ppc_r28", "ppc_r29", - "ppc_r30", "ppc_r31" + static const char rnames[][4] = { + "r0", "sp", "r2", "r3", "r4", + "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", + "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", + "r25", "r26", "r27", "r28", "r29", + "r30", "r31" + }; + if (reg >= 0 && reg < 32) + return rnames [reg]; + return "unknown"; +} + +const char* +mono_arch_fregname (int reg) { + static const char rnames[][4] = { + "f0", "f1", "f2", "f3", "f4", + "f5", "f6", "f7", "f8", "f9", + "f10", "f11", "f12", "f13", "f14", + "f15", "f16", "f17", "f18", "f19", + "f20", "f21", "f22", "f23", "f24", + "f25", "f26", "f27", "f28", "f29", + "f30", "f31" }; if (reg >= 0 && reg < 32) return rnames [reg]; @@ -214,7 +235,7 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask) guint32 opts = 0; /* no ppc-specific optimizations yet */ - *exclude_mask = MONO_OPT_INLINE; + *exclude_mask = 0; return opts; } @@ -237,6 +258,10 @@ is_regsize_var (MonoType *t) { case MONO_TYPE_SZARRAY: case MONO_TYPE_ARRAY: return TRUE; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (t)) + return TRUE; + return FALSE; case MONO_TYPE_VALUETYPE: return FALSE; } @@ -271,9 +296,6 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) return vars; } -#define USE_EXTRA_TEMPS ((1<<30) | (1<<29)) -//#define USE_EXTRA_TEMPS 0 - GList * mono_arch_get_global_int_regs (MonoCompile *cfg) { @@ -281,9 +303,6 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) int i, top = 32; if (cfg->frame_reg != ppc_sp) top = 31; -#if USE_EXTRA_TEMPS - top = 29; -#endif for (i = 13; i < top; ++i) regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); @@ -304,29 +323,67 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv) return 2; } -// code from ppc/tramp.c, try to keep in sync -#define MIN_CACHE_LINE 8 +typedef struct { + long int type; + long int value; +} AuxVec; void mono_arch_flush_icache (guint8 *code, gint size) { - guint i; - guint8 *p; + guint8 *p, *endp, *start; + static int cachelinesize = 0; + static int cachelineinc = 16; - p = code; + if (!cachelinesize) { +#ifdef __APPLE__ + int mib [3], len; + mib [0] = CTL_HW; + mib [1] = HW_CACHELINE; + len = sizeof (cachelinesize); + if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) { + perror ("sysctl"); + cachelinesize = 128; + } else { + cachelineinc = cachelinesize; + /*g_print ("setting cl size to %d\n", cachelinesize);*/ + } +#elif defined(__linux__) + /* sadly this will work only with 2.6 kernels... */ + FILE* f = fopen ("/proc/self/auxv", "rb"); + if (f) { + AuxVec vec; + while (fread (&vec, sizeof (vec), 1, f) == 1) { + if (vec.type == 19) { + cachelinesize = vec.value; + break; + } + } + fclose (f); + } + if (!cachelinesize) + cachelinesize = 128; +#else +#warning Need a way to get cache line size + cachelinesize = 128; +#endif + } + p = start = code; + endp = p + size; + start = (guint8*)((guint32)start & ~(cachelinesize - 1)); /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */ if (1) { - for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) { + for (p = start; p < endp; p += cachelineinc) { asm ("dcbf 0,%0;" : : "r"(p) : "memory"); } } else { - for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) { + for (p = start; p < endp; p += cachelineinc) { asm ("dcbst 0,%0;" : : "r"(p) : "memory"); } } asm ("sync"); p = code; - for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) { + for (p = start; p < endp; p += cachelineinc) { asm ("icbi 0,%0; sync;" : : "r"(p) : "memory"); } asm ("sync"); @@ -341,7 +398,7 @@ mono_arch_flush_icache (guint8 *code, gint size) #define FP_ALSO_IN_REG(s) s #else #define ALWAYS_ON_STACK(s) -#define FP_ALSO_IN_REG(s) s +#define FP_ALSO_IN_REG(s) #define ALIGN_DOUBLES #endif @@ -355,7 +412,7 @@ enum { typedef struct { gint32 offset; - guint16 vtsize; /* in param area */ + guint32 vtsize; /* in param area */ guint8 reg; guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */ guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */ @@ -407,6 +464,25 @@ add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple) (*gr) ++; } +#if __APPLE__ +/* size == 4 is checked already */ +static gboolean +has_only_a_r4_field (MonoClass *klass) +{ + gpointer iter; + MonoClassField *f; + iter = NULL; + while ((f = mono_class_get_fields (klass, &iter))) { + if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) { + if (!f->type->byref && f->type->type == MONO_TYPE_R4) + return TRUE; + return FALSE; + } + } + return FALSE; +} +#endif + static CallInfo* calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) { @@ -447,7 +523,6 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) continue; } simpletype = mono_type_get_underlying_type (sig->params [i])->type; - enum_calc_size: switch (simpletype) { case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: @@ -482,6 +557,14 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) add_general (&gr, &stack_size, cinfo->args + n, TRUE); n++; break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (sig->params [i])) { + cinfo->args [n].size = sizeof (gpointer); + add_general (&gr, &stack_size, cinfo->args + n, TRUE); + n++; + break; + } + /* Fall through */ case MONO_TYPE_VALUETYPE: { gint size; MonoClass *klass; @@ -490,6 +573,27 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); +#if __APPLE__ + if (size == 4 && has_only_a_r4_field (klass)) { + cinfo->args [n].size = 4; + + /* It was 7, now it is 8 in LinuxPPC */ + if (fr <= PPC_LAST_FPARG_REG) { + cinfo->args [n].regtype = RegTypeFP; + cinfo->args [n].reg = fr; + fr ++; + FP_ALSO_IN_REG (gr ++); + ALWAYS_ON_STACK (stack_size += 4); + } else { + cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size; + cinfo->args [n].regtype = RegTypeBase; + cinfo->args [n].reg = ppc_sp; /* in the caller*/ + stack_size += 4; + } + n++; + break; + } +#endif DEBUG(printf ("load %d bytes struct\n", mono_class_native_size (sig->params [i]->data.klass, NULL))); #if PPC_PASS_STRUCTS_BY_VALUE @@ -518,6 +622,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) #else add_general (&gr, &stack_size, cinfo->args + n, TRUE); cinfo->args [n].regtype = RegTypeStructByAddr; + cinfo->args [n].vtsize = size; #endif n++; break; @@ -547,6 +652,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) #else add_general (&gr, &stack_size, cinfo->args + n, TRUE); cinfo->args [n].regtype = RegTypeStructByAddr; + cinfo->args [n].vtsize = size; #endif n++; break; @@ -599,7 +705,6 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) { simpletype = mono_type_get_underlying_type (sig->ret)->type; -enum_retvalue: switch (simpletype) { case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: @@ -629,6 +734,12 @@ enum_retvalue: cinfo->ret.reg = ppc_f1; cinfo->ret.regtype = RegTypeFP; break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (sig->ret)) { + cinfo->ret.reg = ppc_r3; + break; + } + break; case MONO_TYPE_VALUETYPE: break; case MONO_TYPE_TYPEDBYREF: @@ -661,6 +772,7 @@ mono_arch_allocate_vars (MonoCompile *m) int i, offset, size, align, curinst; int frame_reg = ppc_sp; + m->flags |= MONO_CFG_HAS_SPILLUP; /* allow room for the vararg method args: void* and long/double */ if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method)) @@ -768,9 +880,9 @@ mono_arch_allocate_vars (MonoCompile *m) if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR) continue; - /* inst->unused indicates native sized value types, this is used by the + /* inst->backend.is_pinvoke indicates native sized value types, this is used by the * pinvoke wrappers when they call functions returning structure */ - if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) + if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align); else size = mono_type_size (inst->inst_vtype, &align); @@ -877,35 +989,51 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, in = call->args [i]; arg->cil_code = in->cil_code; arg->inst_left = in; + arg->inst_call = call; arg->type = in->type; /* prepend, we'll need to reverse them later */ arg->next = call->out_args; call->out_args = arg; if (ainfo->regtype == RegTypeGeneral) { - arg->unused = ainfo->reg; + arg->backend.reg3 = ainfo->reg; call->used_iregs |= 1 << ainfo->reg; if (arg->type == STACK_I8) call->used_iregs |= 1 << (ainfo->reg + 1); } else if (ainfo->regtype == RegTypeStructByAddr) { - /* FIXME: where si the data allocated? */ - arg->unused = ainfo->reg; - call->used_iregs |= 1 << ainfo->reg; + if (ainfo->offset) { + MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo)); + arg->opcode = OP_OUTARG_MEMBASE; + ai->reg = ainfo->reg; + ai->size = sizeof (gpointer); + ai->offset = ainfo->offset; + arg->backend.data = ai; + } else { + arg->backend.reg3 = ainfo->reg; + call->used_iregs |= 1 << ainfo->reg; + } } else if (ainfo->regtype == RegTypeStructByVal) { int cur_reg; + MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo)); /* mark the used regs */ for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) { call->used_iregs |= 1 << (ainfo->reg + cur_reg); } arg->opcode = OP_OUTARG_VT; - arg->unused = ainfo->reg | (ainfo->size << 8) | (ainfo->vtsize << 16); - arg->inst_imm = ainfo->offset; + ai->reg = ainfo->reg; + ai->size = ainfo->size; + ai->vtsize = ainfo->vtsize; + ai->offset = ainfo->offset; + arg->backend.data = ai; } else if (ainfo->regtype == RegTypeBase) { - arg->opcode = OP_OUTARG; - arg->unused = ainfo->reg | (ainfo->size << 8); - arg->inst_imm = ainfo->offset; + MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo)); + arg->opcode = OP_OUTARG_MEMBASE; + ai->reg = ainfo->reg; + ai->size = ainfo->size; + ai->offset = ainfo->offset; + arg->backend.data = ai; } else if (ainfo->regtype == RegTypeFP) { arg->opcode = OP_OUTARG_R8; - arg->unused = ainfo->reg; + arg->backend.reg3 = ainfo->reg; call->used_fregs |= 1 << ainfo->reg; if (ainfo->size == 4) { arg->opcode = OP_OUTARG_R8; @@ -1081,7 +1209,10 @@ handle_enum: * going to be perf critical anyway. */ typedef struct { - MonoBasicBlock *bb; + union { + MonoBasicBlock *bb; + const char *exception; + } data; guint32 ip_offset; guint16 b0_cond; guint16 b1_cond; @@ -1102,7 +1233,7 @@ if (ins->flags & MONO_INST_BRLABEL) { \ int br_disp = ins->inst_true_bb->max_offset - offset; \ if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \ MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \ - ovfj->bb = ins->inst_true_bb; \ + ovfj->data.bb = ins->inst_true_bb; \ ovfj->ip_offset = 0; \ ovfj->b0_cond = (b0); \ ovfj->b1_cond = (b1); \ @@ -1127,13 +1258,12 @@ if (ins->flags & MONO_INST_BRLABEL) { \ int br_disp = cfg->bb_exit->max_offset - offset; \ if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \ MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \ - ovfj->bb = NULL; \ + ovfj->data.exception = (exc_name); \ ovfj->ip_offset = code - cfg->native_code; \ ovfj->b0_cond = (b0); \ ovfj->b1_cond = (b1); \ - /* FIXME: test this code */ \ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \ - ppc_b (code, 0); \ + ppc_bl (code, 0); \ cfg->bb_exit->max_offset += 24; \ } else { \ mono_add_patch_info (cfg, code - cfg->native_code, \ @@ -1240,15 +1370,8 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) 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; - } + ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1; + ins->sreg1 = last_ins->sreg1; } break; case OP_LOADU2_MEMBASE: @@ -1256,15 +1379,8 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) 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 { - //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); - ins->opcode = OP_MOVE; - ins->sreg1 = last_ins->sreg1; - } + ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2; + ins->sreg1 = last_ins->sreg1; } break; case CEE_CONV_I4: @@ -1344,780 +1460,253 @@ branch_b1_table [] = { PPC_BR_LT }; -/* - * 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; -} - -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 += 7; - cfg->stack_offset &= ~7; - 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; -} - -#undef DEBUG -#define DEBUG(a) if (cfg->verbose_level > 1) a -//#define DEBUG(a) -/* use ppc_r3-ppc_10,ppc_r12 as temp registers, f1-f13 for FP registers */ -#define PPC_CALLER_REGS ((0xff<<3) | (1<<12) | USE_EXTRA_TEMPS) -#define PPC_CALLER_FREGS (0x3ffe) - -#define reg_is_freeable(r) (PPC_CALLER_REGS & 1 << (r)) -#define freg_is_freeable(r) ((r) >= 1 && (r) <= 13) - -typedef struct { - int born_in; - int killed_in; - int last_use; - int prev_use; -} RegTrack; - -static const char*const * ins_spec = ppcg4; - 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"); -} - -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); - } -} - -typedef struct InstList InstList; - -struct InstList { - InstList *prev; - InstList *next; - MonoInst *data; -}; - -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; -} - -/* - * 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 = cfg->rs->isymbolic [sel]; - g_assert (i == 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; -} - -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; -} - -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 FP (%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; -} - -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; -} - -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; -} - -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; - } - DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg))); - return store; -} - -static MonoInst* -create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins) +insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert) { - MonoInst *store; - MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG); - store->sreg1 = reg; - store->inst_destbasereg = cfg->frame_reg; - store->inst_offset = mono_spillvar_offset_float (cfg, spill); - if (ins) { - store->next = ins->next; - ins->next = store; + if (ins == NULL) { + ins = bb->code; + bb->code = to_insert; + to_insert->next = ins; + } else { + to_insert->next = ins->next; + ins->next = to_insert; } - DEBUG (g_print ("SPILLED STORE FP (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg))); - return store; } -static void -insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert) -{ - MonoInst *prev; - g_assert (item->next); - prev = item->next->data; - - while (prev->next != ins) - prev = prev->next; - to_insert->next = ins; - prev->next = to_insert; - /* - * 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; -} +#define NEW_INS(cfg,dest,op) do { \ + (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \ + (dest)->opcode = (op); \ + insert_after_ins (bb, last_ins, (dest)); \ + } while (0) static int -alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask) +map_to_reg_reg_op (int op) { - int val = cfg->rs->iassign [sym_reg]; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (cfg->rs, allow_mask); - if (val < 0) - val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg); - cfg->rs->iassign [sym_reg] = val; - /* add option to store before the instruction for src registers */ - if (spill) - create_spilled_store (cfg, spill, val, sym_reg, ins); + switch (op) { + case OP_ADD_IMM: + return CEE_ADD; + case OP_SUB_IMM: + return CEE_SUB; + case OP_AND_IMM: + return CEE_AND; + case OP_COMPARE_IMM: + return OP_COMPARE; + case OP_ADDCC_IMM: + return OP_ADDCC; + case OP_ADC_IMM: + return OP_ADC; + case OP_SUBCC_IMM: + return OP_SUBCC; + case OP_SBB_IMM: + return OP_SBB; + case OP_OR_IMM: + return CEE_OR; + case OP_XOR_IMM: + return CEE_XOR; + case OP_MUL_IMM: + return CEE_MUL; + case OP_LOAD_MEMBASE: + return OP_LOAD_MEMINDEX; + case OP_LOADI4_MEMBASE: + return OP_LOADI4_MEMINDEX; + case OP_LOADU4_MEMBASE: + return OP_LOADU4_MEMINDEX; + case OP_LOADU1_MEMBASE: + return OP_LOADU1_MEMINDEX; + case OP_LOADI2_MEMBASE: + return OP_LOADI2_MEMINDEX; + case OP_LOADU2_MEMBASE: + return OP_LOADU2_MEMINDEX; + case OP_LOADI1_MEMBASE: + return OP_LOADI1_MEMINDEX; + case OP_LOADR4_MEMBASE: + return OP_LOADR4_MEMINDEX; + case OP_LOADR8_MEMBASE: + return OP_LOADR8_MEMINDEX; + case OP_STOREI1_MEMBASE_REG: + return OP_STOREI1_MEMINDEX; + case OP_STOREI2_MEMBASE_REG: + return OP_STOREI2_MEMINDEX; + case OP_STOREI4_MEMBASE_REG: + return OP_STOREI4_MEMINDEX; + case OP_STORE_MEMBASE_REG: + return OP_STORE_MEMINDEX; + case OP_STORER4_MEMBASE_REG: + return OP_STORER4_MEMINDEX; + case OP_STORER8_MEMBASE_REG: + return OP_STORER8_MEMINDEX; + case OP_STORE_MEMBASE_IMM: + return OP_STORE_MEMBASE_REG; + case OP_STOREI1_MEMBASE_IMM: + return OP_STOREI1_MEMBASE_REG; + case OP_STOREI2_MEMBASE_IMM: + return OP_STOREI2_MEMBASE_REG; + case OP_STOREI4_MEMBASE_IMM: + return OP_STOREI4_MEMBASE_REG; } - cfg->rs->isymbolic [val] = sym_reg; - return val; + g_assert_not_reached (); } +#define compare_opcode_is_unsigned(opcode) \ + (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \ + ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \ + ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN)) /* - * 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. + * Remove from the instruction list the instructions that can't be + * represented with very simple instructions with no register + * requirements. */ -void -mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) +static void +mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoInst *ins; - MonoRegState *rs = cfg->rs; - int i, val; - RegTrack *reginfo, *reginfof; - RegTrack *reginfo1, *reginfo2, *reginfod; - InstList *tmp, *reversed = NULL; - const char *spec; - guint32 src1_mask, src2_mask, dest_mask; - guint32 cur_iregs, cur_fregs; + MonoInst *ins, *next, *temp, *last_ins = NULL; + int imm; - if (!bb->code) - return; - rs->next_vireg = bb->max_ireg; - rs->next_vfreg = bb->max_freg; - mono_regstate_assign (rs); - reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg); - reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg); - rs->ifree_mask = PPC_CALLER_REGS; - rs->ffree_mask = PPC_CALLER_FREGS; + /* setup the virtual reg allocator */ + if (bb->max_vreg > cfg->rs->next_vreg) + cfg->rs->next_vreg = bb->max_vreg; ins = bb->code; - i = 1; - 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_CLOB] == 'c') { - MonoCallInst * call = (MonoCallInst*)ins; - int j; - }*/ - 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; - } else { - ins->sreg1 = -1; - } - if (spec [MONO_INST_SRC2]) { - if (spec [MONO_INST_SRC2] == 'f') - reginfo2 = reginfof; - else - reginfo2 = reginfo; - reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use; - reginfo2 [ins->sreg2].last_use = i; - } else { - ins->sreg2 = -1; - } - if (spec [MONO_INST_DEST]) { - if (spec [MONO_INST_DEST] == 'f') - 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; - 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') { - /* result in eax:edx, 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; - } - } else { - ins->dreg = -1; - } - reversed = inst_list_prepend (cfg->mempool, reversed, ins); - ++i; - ins = ins->next; - } - - cur_iregs = PPC_CALLER_REGS; - cur_fregs = PPC_CALLER_FREGS; - - 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; - --i; - ins = tmp->data; - spec = ins_spec [ins->opcode]; - DEBUG (g_print ("processing:")); - DEBUG (print_ins (i, ins)); - /* make the register available for allocation: FIXME add fp reg */ - if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) { - cur_iregs |= 1 << ins->dreg; - DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg)); - } else if (ins->opcode == OP_SETFREG) { - cur_fregs |= 1 << ins->dreg; - DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg)); - } else if (spec [MONO_INST_CLOB] == 'c') { - MonoCallInst *cinst = (MonoCallInst*)ins; - DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst->used_iregs, cur_iregs)); - DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n", cinst->used_fregs, cur_fregs)); - cur_iregs &= ~cinst->used_iregs; - cur_fregs &= ~cinst->used_fregs; - DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs)); - DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs)); - /* registers used by the calling convention are excluded from - * allocation: they will be selectively enabled when they are - * assigned by the special SETREG opcodes. - */ - } - dest_mask = src1_mask = src2_mask = cur_iregs; - /* update for use with FP regs... */ - if (spec [MONO_INST_DEST] == 'f') { - dest_mask = cur_fregs; - if (ins->dreg >= MONO_MAX_FREGS) { - 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_regstate_alloc_float (rs, dest_mask); - if (val < 0) - val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg); - rs->fassign [ins->dreg] = val; - if (spill) - create_spilled_store_float (cfg, spill, val, prev_dreg, ins); - } - DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg)); - rs->fsymbolic [val] = prev_dreg; - ins->dreg = val; - if (spec [MONO_INST_CLOB] == 'c' && ins->dreg != ppc_f1) { - /* this instruction only outputs to ppc_f1, need to copy */ - create_copy_ins_float (cfg, ins->dreg, ppc_f1, ins); - } - } else { - prev_dreg = -1; - } - if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) { - DEBUG (g_print ("\tfreeable float %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfof [prev_dreg].born_in)); - mono_regstate_free_float (rs, ins->dreg); +loop_start: + switch (ins->opcode) { + case OP_ADD_IMM: + case OP_ADDCC_IMM: + if (!ppc_is_imm16 (ins->inst_imm)) { + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); } - } else if (ins->dreg >= MONO_MAX_IREGS) { - val = rs->iassign [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_regstate_alloc_int (rs, dest_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg); - rs->iassign [ins->dreg] = val; - if (spill) - create_spilled_store (cfg, spill, val, prev_dreg, ins); + break; + case OP_SUB_IMM: + if (!ppc_is_imm16 (-ins->inst_imm)) { + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); } - 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; - if (spec [MONO_INST_DEST] == 'l') { - 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_regstate_alloc_int (rs, dest_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg); - rs->iassign [hreg] = val; - if (spill) - create_spilled_store (cfg, spill, val, hreg, ins); - } - DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg)); - rs->isymbolic [val] = hreg; - /* FIXME:? ins->dreg = val; */ - if (ins->dreg == ppc_r4) { - if (val != ppc_r3) - create_copy_ins (cfg, val, ppc_r3, ins); - } else if (ins->dreg == ppc_r3) { - if (val == ppc_r4) { - /* swap */ - create_copy_ins (cfg, ppc_r4, ppc_r0, ins); - create_copy_ins (cfg, ppc_r3, ppc_r4, ins); - create_copy_ins (cfg, ppc_r0, ppc_r3, ins); - } else { - /* two forced copies */ - create_copy_ins (cfg, ins->dreg, ppc_r4, ins); - create_copy_ins (cfg, val, ppc_r3, ins); - } - } else { - if (val == ppc_r3) { - create_copy_ins (cfg, ins->dreg, ppc_r4, ins); - } else { - /* two forced copies */ - create_copy_ins (cfg, val, ppc_r3, ins); - create_copy_ins (cfg, ins->dreg, ppc_r4, ins); - } - } - if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) { - 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 != ppc_r3 && spec [MONO_INST_CLOB] != 'd') { - /* this instruction only outputs to ppc_r3, need to copy */ - create_copy_ins (cfg, ins->dreg, ppc_r3, ins); + break; + case OP_AND_IMM: + case OP_OR_IMM: + case OP_XOR_IMM: + if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) { + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); } - } else { - prev_dreg = -1; - } - if (spec [MONO_INST_DEST] == 'f' && freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i)) { - DEBUG (g_print ("\tfreeable float %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfof [prev_dreg].born_in)); - mono_regstate_free_float (rs, ins->dreg); - } else if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && 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); - } - if (spec [MONO_INST_SRC1] == 'f') { - src1_mask = cur_fregs; - if (ins->sreg1 >= MONO_MAX_FREGS) { - 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; - } - //g_assert (val == -1); /* source cannot be spilled */ - val = mono_regstate_alloc_float (rs, src1_mask); - if (val < 0) - val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1); - rs->fassign [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_float (cfg, spill, val, prev_sreg1, NULL); - insert_before_ins (ins, tmp, store); - } + break; + case OP_SBB_IMM: + case OP_SUBCC_IMM: + case OP_ADC_IMM: + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); + break; + case OP_COMPARE_IMM: + if (compare_opcode_is_unsigned (ins->next->opcode)) { + if (!ppc_is_uimm16 (ins->inst_imm)) { + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); } - rs->fsymbolic [val] = prev_sreg1; - ins->sreg1 = val; } else { - prev_sreg1 = -1; - } - } 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_regstate_alloc_int (rs, src1_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1); - 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); - insert_before_ins (ins, tmp, store); + if (!ppc_is_imm16 (ins->inst_imm)) { + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); } } - rs->isymbolic [val] = prev_sreg1; - ins->sreg1 = val; - } else { - prev_sreg1 = -1; - } - if (spec [MONO_INST_SRC2] == 'f') { - src2_mask = cur_fregs; - if (ins->sreg2 >= MONO_MAX_FREGS) { - val = rs->fassign [ins->sreg2]; - prev_sreg2 = ins->sreg2; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_float (rs, src2_mask); - if (val < 0) - val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2); - rs->fassign [ins->sreg2] = val; - DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2)); - if (spill) - create_spilled_store_float (cfg, spill, val, prev_sreg2, ins); - } - rs->fsymbolic [val] = prev_sreg2; - ins->sreg2 = val; - } else { - prev_sreg2 = -1; + break; + case OP_MUL_IMM: + if (ins->inst_imm == 1) { + ins->opcode = OP_MOVE; + break; } - } else if (ins->sreg2 >= MONO_MAX_IREGS) { - val = rs->iassign [ins->sreg2]; - prev_sreg2 = ins->sreg2; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (rs, src2_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2); - rs->iassign [ins->sreg2] = val; - DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2)); - if (spill) - create_spilled_store (cfg, spill, val, prev_sreg2, ins); + if (ins->inst_imm == 0) { + ins->opcode = OP_ICONST; + ins->inst_c0 = 0; + break; } - rs->isymbolic [val] = prev_sreg2; - ins->sreg2 = val; - } else { - prev_sreg2 = -1; - } - - if (spec [MONO_INST_CLOB] == 'c') { - int j, s; - guint32 clob_mask = PPC_CALLER_REGS; - for (j = 0; j < MONO_MAX_IREGS; ++j) { - s = 1 << j; - if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) { - //g_warning ("register %s busy at call site\n", mono_arch_regname (j)); - } + imm = mono_is_power_of_two (ins->inst_imm); + if (imm > 0) { + ins->opcode = OP_SHL_IMM; + ins->inst_imm = imm; + break; } + if (!ppc_is_imm16 (ins->inst_imm)) { + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); + } + break; + case OP_LOAD_MEMBASE: + case OP_LOADI4_MEMBASE: + case OP_LOADU4_MEMBASE: + case OP_LOADI2_MEMBASE: + case OP_LOADU2_MEMBASE: + case OP_LOADI1_MEMBASE: + case OP_LOADU1_MEMBASE: + case OP_LOADR4_MEMBASE: + case OP_LOADR8_MEMBASE: + case OP_STORE_MEMBASE_REG: + case OP_STOREI4_MEMBASE_REG: + case OP_STOREI2_MEMBASE_REG: + case OP_STOREI1_MEMBASE_REG: + case OP_STORER4_MEMBASE_REG: + case OP_STORER8_MEMBASE_REG: + /* we can do two things: load the immed in a register + * and use an indexed load, or see if the immed can be + * represented as an ad_imm + a load with a smaller offset + * that fits. We just do the first for now, optimize later. + */ + if (ppc_is_imm16 (ins->inst_offset)) + break; + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_offset; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg2 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); + break; + case OP_STORE_MEMBASE_IMM: + case OP_STOREI1_MEMBASE_IMM: + case OP_STOREI2_MEMBASE_IMM: + case OP_STOREI4_MEMBASE_IMM: + NEW_INS (cfg, temp, OP_ICONST); + temp->inst_c0 = ins->inst_imm; + temp->dreg = mono_regstate_next_int (cfg->rs); + ins->sreg1 = temp->dreg; + ins->opcode = map_to_reg_reg_op (ins->opcode); + last_ins = temp; + goto loop_start; /* make it handle the possibly big ins->inst_offset */ } - /*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); - } - 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 (print_ins (i, ins)); - tmp = tmp->next; + last_ins = ins; + ins = ins->next; } - cfg->max_ireg = MAX (cfg->max_ireg, rs->max_ireg); + bb->last_ins = last_ins; + bb->max_vreg = cfg->rs->next_vreg; + +} + +void +mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) +{ + if (!bb->code) + return; + mono_arch_lowering_pass (cfg, bb); + mono_local_regalloc (cfg, bb); } static guchar* @@ -2221,6 +1810,12 @@ search_thunk_slot (void *data, int csize, int bsize, void *user_data) { ppc_patch (pdata->code, (guchar*)thunks); mono_arch_flush_icache (pdata->code, 4); pdata->found = 1; + /*{ + static int num_thunks = 0; + num_thunks++; + if ((num_thunks % 20) == 0) + g_print ("num_thunks lookup: %d\n", num_thunks); + }*/ return 1; } else if ((thunks [0] == 0) && (thunks [1] == 0)) { /* found a free slot instead: emit thunk */ @@ -2234,6 +1829,12 @@ search_thunk_slot (void *data, int csize, int bsize, void *user_data) { ppc_patch (pdata->code, (guchar*)thunks); mono_arch_flush_icache (pdata->code, 4); pdata->found = 1; + /*{ + static int num_thunks = 0; + num_thunks++; + if ((num_thunks % 20) == 0) + g_print ("num_thunks: %d\n", num_thunks); + }*/ return 1; } /* skip 16 bytes, the size of the thunk */ @@ -2341,10 +1942,10 @@ ppc_patch (guchar *code, guchar *target) return; } - if (prim == 15 || ins == 0x4e800021) { + if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) { guint32 *seq; - /* the trampoline code will try to patch the blrl */ - if (ins == 0x4e800021) { + /* the trampoline code will try to patch the blrl, blr, bcctr */ + if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) { code -= 12; } /* this is the lis/ori/mtlr/blrl sequence */ @@ -2352,7 +1953,7 @@ ppc_patch (guchar *code, guchar *target) g_assert ((seq [0] >> 26) == 15); g_assert ((seq [1] >> 26) == 24); g_assert ((seq [2] >> 26) == 31); - g_assert (seq [3] == 0x4e800021); + g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420); /* FIXME: make this thread safe */ ppc_lis (code, ppc_r0, (guint32)(target) >> 16); ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff); @@ -2399,7 +2000,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) while (ins) { offset = code - cfg->native_code; - max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN]; + max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; if (offset > (cfg->code_size - max_len - 16)) { cfg->code_size *= 2; @@ -2415,55 +2016,30 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) emit_tls_access (code, ins->dreg, ins->inst_offset); break; case OP_BIGMUL: - ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2); + ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2); ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2); + ppc_mr (code, ppc_r4, ppc_r0); break; case OP_BIGMUL_UN: - ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2); + ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2); ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2); + ppc_mr (code, ppc_r4, ppc_r0); break; - case OP_STOREI1_MEMBASE_IMM: - ppc_li (code, ppc_r0, ins->inst_imm); - if (ppc_is_imm16 (ins->inst_offset)) { - ppc_stb (code, ppc_r0, ins->inst_offset, ins->inst_destbasereg); - } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_stbx (code, ppc_r0, ppc_r11, ins->inst_destbasereg); - } - break; - case OP_STOREI2_MEMBASE_IMM: - ppc_li (code, ppc_r0, ins->inst_imm); - if (ppc_is_imm16 (ins->inst_offset)) { - ppc_sth (code, ppc_r0, ins->inst_offset, ins->inst_destbasereg); - } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_sthx (code, ppc_r0, ppc_r11, ins->inst_destbasereg); - } - break; - case OP_STORE_MEMBASE_IMM: - case OP_STOREI4_MEMBASE_IMM: - ppc_load (code, ppc_r0, ins->inst_imm); - if (ppc_is_imm16 (ins->inst_offset)) { - ppc_stw (code, ppc_r0, ins->inst_offset, ins->inst_destbasereg); - } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_destbasereg); - } + case OP_MEMORY_BARRIER: + ppc_sync (code); break; case OP_STOREI1_MEMBASE_REG: if (ppc_is_imm16 (ins->inst_offset)) { ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_stbx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg); + g_assert_not_reached (); } break; case OP_STOREI2_MEMBASE_REG: if (ppc_is_imm16 (ins->inst_offset)) { ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_sthx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg); + g_assert_not_reached (); } break; case OP_STORE_MEMBASE_REG: @@ -2471,10 +2047,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_offset)) { ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_stwx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg); + g_assert_not_reached (); } break; + case OP_STOREI1_MEMINDEX: + ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg); + break; + case OP_STOREI2_MEMINDEX: + ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg); + break; + case OP_STORE_MEMINDEX: + case OP_STOREI4_MEMINDEX: + ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg); + break; case CEE_LDIND_I: case CEE_LDIND_I4: case CEE_LDIND_U4: @@ -2483,8 +2068,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LOADU4_MEM: g_assert_not_reached (); - //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0); - //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4); break; case OP_LOAD_MEMBASE: case OP_LOADI4_MEMBASE: @@ -2492,8 +2075,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_offset)) { ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_lwzx (code, ins->dreg, ppc_r11, ins->inst_basereg); + g_assert_not_reached (); } break; case OP_LOADI1_MEMBASE: @@ -2501,8 +2083,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_offset)) { ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_lbzx (code, ins->dreg, ppc_r11, ins->inst_basereg); + g_assert_not_reached (); } if (ins->opcode == OP_LOADI1_MEMBASE) ppc_extsb (code, ins->dreg, ins->dreg); @@ -2511,18 +2092,34 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_offset)) { ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_lhzx (code, ins->dreg, ppc_r11, ins->inst_basereg); + g_assert_not_reached (); } break; case OP_LOADI2_MEMBASE: if (ppc_is_imm16 (ins->inst_offset)) { ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_lhax (code, ins->dreg, ppc_r11, ins->inst_basereg); + g_assert_not_reached (); } break; + case OP_LOAD_MEMINDEX: + case OP_LOADI4_MEMINDEX: + case OP_LOADU4_MEMINDEX: + ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg); + break; + case OP_LOADU2_MEMINDEX: + ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg); + break; + case OP_LOADI2_MEMINDEX: + ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg); + break; + case OP_LOADU1_MEMINDEX: + ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg); + break; + case OP_LOADI1_MEMINDEX: + ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg); + ppc_extsb (code, ins->dreg, ins->dreg); + break; case CEE_CONV_I1: ppc_extsb (code, ins->dreg, ins->sreg1); break; @@ -2536,37 +2133,26 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31); break; case OP_COMPARE: - if (ins->next && - ((ins->next->opcode >= CEE_BNE_UN && ins->next->opcode <= CEE_BLT_UN) || - (ins->next->opcode >= OP_COND_EXC_NE_UN && ins->next->opcode <= OP_COND_EXC_LT_UN) || - (ins->next->opcode == OP_CLT_UN || ins->next->opcode == OP_CGT_UN))) + if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2); else ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2); break; case OP_COMPARE_IMM: - if (ins->next && - ((ins->next->opcode >= CEE_BNE_UN && ins->next->opcode <= CEE_BLT_UN) || - (ins->next->opcode >= OP_COND_EXC_NE_UN && ins->next->opcode <= OP_COND_EXC_LT_UN) || - (ins->next->opcode == OP_CLT_UN || ins->next->opcode == OP_CGT_UN))) { + if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) { if (ppc_is_uimm16 (ins->inst_imm)) { ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff)); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_cmpl (code, 0, 0, ins->sreg1, ppc_r11); + g_assert_not_reached (); } } else { if (ppc_is_imm16 (ins->inst_imm)) { ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff)); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11); + g_assert_not_reached (); } } break; - case OP_X86_TEST_NULL: - ppc_cmpi (code, 0, 0, ins->sreg1, 0); - break; case CEE_BREAK: ppc_break (code); break; @@ -2583,22 +2169,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_imm)) { ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_addc (code, ins->dreg, ins->sreg1, ppc_r11); + g_assert_not_reached (); } break; case OP_ADD_IMM: if (ppc_is_imm16 (ins->inst_imm)) { ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_add (code, ins->dreg, ins->sreg1, ppc_r11); + g_assert_not_reached (); } break; - case OP_ADC_IMM: - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_adde (code, ins->dreg, ins->sreg1, ppc_r11); - break; case CEE_ADD_OVF: /* check XER [0-3] (SO, OV, CA): we can't use mcrxr */ @@ -2666,10 +2246,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_SUBCC: ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1); break; - case OP_SUBCC_IMM: - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_subfc (code, ins->dreg, ppc_r11, ins->sreg1); - break; case CEE_SUB: ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1); break; @@ -2681,14 +2257,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (-ins->inst_imm)) ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm); else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_sub (code, ins->dreg, ins->sreg1, ppc_r11); + g_assert_not_reached (); } break; - case OP_SBB_IMM: - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_subfe (code, ins->dreg, ppc_r11, ins->sreg1); - break; case OP_PPC_SUBFIC: g_assert (ppc_is_imm16 (ins->inst_imm)); ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm); @@ -2706,8 +2277,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } else if (!(ins->inst_imm & 0xffff)) { ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16)); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_and (code, ins->sreg1, ins->dreg, ppc_r11); + g_assert_not_reached (); } break; case CEE_DIV: { @@ -2781,10 +2351,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (!(ins->inst_imm & 0xffff0000)) { ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm); } else if (!(ins->inst_imm & 0xffff)) { - ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16)); + ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16)); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_or (code, ins->sreg1, ins->dreg, ppc_r11); + g_assert_not_reached (); } break; case CEE_XOR: @@ -2796,8 +2365,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } else if (!(ins->inst_imm & 0xffff)) { ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16)); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_xor (code, ins->sreg1, ins->dreg, ppc_r11); + g_assert_not_reached (); } break; case CEE_SHL: @@ -2805,21 +2373,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_SHL_IMM: ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f))); - //ppc_load (code, ppc_r11, ins->inst_imm); - //ppc_slw (code, ins->sreg1, ins->dreg, ppc_r11); break; case CEE_SHR: ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2); break; case OP_SHR_IMM: - // there is also ppc_srawi - //ppc_load (code, ppc_r11, ins->inst_imm); - //ppc_sraw (code, ins->dreg, ins->sreg1, ppc_r11); ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f)); break; case OP_SHR_UN_IMM: - /*ppc_load (code, ppc_r11, ins->inst_imm); - ppc_srw (code, ins->dreg, ins->sreg1, ppc_r11);*/ ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31); break; case CEE_SHR_UN: @@ -2838,8 +2399,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_imm)) { ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm); } else { - ppc_load (code, ppc_r11, ins->inst_imm); - ppc_mullw (code, ins->dreg, ins->sreg1, ppc_r11); + g_assert_not_reached (); } break; case CEE_MUL_OVF: @@ -2961,7 +2521,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method); else mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr); - if (cfg->method->dynamic) { + if (FORCE_INDIR_CALL || cfg->method->dynamic) { ppc_lis (code, ppc_r0, 0); ppc_ori (code, ppc_r0, ppc_r0, 0); ppc_mtlr (code, ppc_r0); @@ -2991,7 +2551,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert_not_reached (); break; case OP_LOCALLOC: { - guint32 * zero_loop_jump, zero_loop_start; + guint32 * zero_loop_jump, * zero_loop_start; /* keep alignment */ int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31; int area_offset = alloca_waste; @@ -3030,7 +2590,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_mr (code, ppc_r3, ins->sreg1); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_arch_throw_exception"); - if (cfg->method->dynamic) { + if (FORCE_INDIR_CALL || cfg->method->dynamic) { ppc_lis (code, ppc_r0, 0); ppc_ori (code, ppc_r0, ppc_r0, 0); ppc_mtlr (code, ppc_r0); @@ -3045,7 +2605,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_mr (code, ppc_r3, ins->sreg1); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_arch_rethrow_exception"); - if (cfg->method->dynamic) { + if (FORCE_INDIR_CALL || cfg->method->dynamic) { ppc_lis (code, ppc_r0, 0); ppc_ori (code, ppc_r0, ppc_r0, 0); ppc_mtlr (code, ppc_r0); @@ -3184,34 +2744,44 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ppc_is_imm16 (ins->inst_offset)) { ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_stfdx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg); + g_assert_not_reached (); } break; case OP_LOADR8_MEMBASE: if (ppc_is_imm16 (ins->inst_offset)) { ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_lfdx (code, ins->dreg, ppc_r11, ins->inst_basereg); + g_assert_not_reached (); } break; case OP_STORER4_MEMBASE_REG: + ppc_frsp (code, ins->sreg1, ins->sreg1); if (ppc_is_imm16 (ins->inst_offset)) { ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_stfsx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg); + g_assert_not_reached (); } break; case OP_LOADR4_MEMBASE: if (ppc_is_imm16 (ins->inst_offset)) { ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg); } else { - ppc_load (code, ppc_r11, ins->inst_offset); - ppc_lfsx (code, ins->dreg, ppc_r11, ins->inst_basereg); + g_assert_not_reached (); } break; + case OP_LOADR4_MEMINDEX: + ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg); + break; + case OP_LOADR8_MEMINDEX: + ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg); + break; + case OP_STORER4_MEMINDEX: + ppc_frsp (code, ins->sreg1, ins->sreg1); + ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg); + break; + case OP_STORER8_MEMINDEX: + ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg); + break; case CEE_CONV_R_UN: { static const guint64 adjust_val = 0x4330000000000000ULL; ppc_addis (code, ppc_r0, ppc_r0, 0x4330); @@ -3237,14 +2807,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0); break; } - case OP_X86_FP_LOAD_I8: - g_assert_not_reached (); - /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);*/ - break; - case OP_X86_FP_LOAD_I4: - g_assert_not_reached (); - /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);*/ - break; case OP_FCONV_TO_I1: code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE); break; @@ -3322,7 +2884,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert_not_reached (); break; case OP_FCOMPARE: - ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2); + ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2); break; case OP_FCEQ: ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2); @@ -3363,6 +2925,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ); break; case OP_FBLT: + ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2); EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ); break; case OP_FBLT_UN: @@ -3370,6 +2933,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ); break; case OP_FBGT: + ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2); EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ); break; case OP_FBGT_UN: @@ -3377,12 +2941,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ); break; case OP_FBGE: + ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2); EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ); break; case OP_FBGE_UN: EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ); break; case OP_FBLE: + ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2); EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ); break; case OP_FBLE_UN: @@ -3453,9 +3019,7 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono gpointer *table = (gpointer *)patch_info->data.table->table; int i; - // FIXME: inspect code to get the register - ppc_load (ip, ppc_r11, table); - //*((gconstpointer *)(ip + 2)) = patch_info->data.target; + patch_lis_ori (ip, table); for (i = 0; i < patch_info->data.table->table_size; i++) { table [i] = (int)patch_info->data.table->table [i] + code; @@ -3539,8 +3103,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) ppc_mflr (code, ppc_r0); ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp); } - if (cfg->max_ireg >= 29) - cfg->used_int_regs |= USE_EXTRA_TEMPS; alloc_size = cfg->stack_offset; pos = 0; @@ -3601,7 +3163,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) max_offset += 6; while (ins) { - max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN]; + max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; ins = ins->next; } } @@ -3760,17 +3322,37 @@ register. Should this case include linux/ppc? code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset); } } else if (ainfo->regtype == RegTypeStructByAddr) { + /* if it was originally a RegTypeBase */ + if (ainfo->offset) { + /* load the previous stack pointer in r11 */ + ppc_lwz (code, ppc_r11, 0, ppc_sp); + ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11); + } else { + ppc_mr (code, ppc_r11, ainfo->reg); + } g_assert (ppc_is_imm16 (inst->inst_offset)); - /* FIXME: handle overrun! with struct sizes not multiple of 4 */ - code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0); + code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0); + /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/ } else g_assert_not_reached (); } pos++; } - if (method->save_lmf) { + if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) { + ppc_load (code, ppc_r3, cfg->domain); + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach"); + if (FORCE_INDIR_CALL || cfg->method->dynamic) { + ppc_lis (code, ppc_r0, 0); + ppc_ori (code, ppc_r0, ppc_r0, 0); + ppc_mtlr (code, ppc_r0); + ppc_blrl (code); + } else { + ppc_bl (code, 0); + } + } + if (method->save_lmf) { if (lmf_pthread_key != -1) { emit_tls_access (code, ppc_r3, lmf_pthread_key); if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) @@ -3778,7 +3360,7 @@ register. Should this case include linux/ppc? } else { mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr"); - if (cfg->method->dynamic) { + if (FORCE_INDIR_CALL || cfg->method->dynamic) { ppc_lis (code, ppc_r0, 0); ppc_ori (code, ppc_r0, ppc_r0, 0); ppc_mtlr (code, ppc_r0); @@ -3942,6 +3524,7 @@ exception_id_by_name (const char *name) if (strcmp (name, "ArrayTypeMismatchException") == 0) return MONO_EXC_ARRAY_TYPE_MISMATCH; g_error ("Unknown intrinsic exception %s\n", name); + return 0; } void @@ -3966,13 +3549,20 @@ mono_arch_emit_exceptions (MonoCompile *cfg) if (patch_info->type == MONO_PATCH_INFO_EXC) { i = exception_id_by_name (patch_info->data.target); if (!exc_throw_found [i]) { - max_epilog_size += 12; + max_epilog_size += 24; exc_throw_found [i] = TRUE; } } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF) max_epilog_size += 12; - else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) - max_epilog_size += 12; + else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) { + MonoOvfJump *ovfj = patch_info->data.target; + i = exception_id_by_name (ovfj->data.exception); + if (!exc_throw_found [i]) { + max_epilog_size += 24; + exc_throw_found [i] = TRUE; + } + max_epilog_size += 8; + } } while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) { @@ -3996,22 +3586,28 @@ mono_arch_emit_exceptions (MonoCompile *cfg) ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */ /* jump back to the true target */ ppc_b (code, 0); - ip = ovfj->bb->native_offset + cfg->native_code; + ip = ovfj->data.bb->native_offset + cfg->native_code; ppc_patch (code - 4, ip); break; } case MONO_PATCH_INFO_EXC_OVF: { MonoOvfJump *ovfj = patch_info->data.target; + MonoJumpInfo *newji; unsigned char *ip = patch_info->ip.i + cfg->native_code; - /* patch the initial jump */ + unsigned char *bcl = code; + /* patch the initial jump: we arrived here with a call */ ppc_patch (ip, code); - ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2); + ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0); ppc_b (code, 0); ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */ - /* jump back to the true target */ - ppc_b (code, 0); - ip = cfg->native_code + ovfj->ip_offset + 4; - ppc_patch (code - 4, ip); + /* patch the conditional jump to the right handler */ + /* make it processed next */ + newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo)); + newji->type = MONO_PATCH_INFO_EXC; + newji->ip.i = bcl - cfg->native_code; + newji->data.target = ovfj->data.exception; + newji->next = patch_info->next; + patch_info->next = newji; break; } case MONO_PATCH_INFO_EXC: { @@ -4031,7 +3627,14 @@ mono_arch_emit_exceptions (MonoCompile *cfg) patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD; patch_info->data.name = "mono_arch_throw_exception_by_name"; patch_info->ip.i = code - cfg->native_code; - ppc_b (code, 0); + if (FORCE_INDIR_CALL || cfg->method->dynamic) { + ppc_lis (code, ppc_r0, 0); + ppc_ori (code, ppc_r0, ppc_r0, 0); + ppc_mtctr (code, ppc_r0); + ppc_bcctr (code, PPC_BR_ALWAYS, 0); + } else { + ppc_b (code, 0); + } break; } default: @@ -4206,8 +3809,9 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re MONO_INST_NEW (cfg, this, OP_SETREG); this->type = this_type; this->sreg1 = this_reg; - this->dreg = this_dreg; + this->dreg = mono_regstate_next_int (cfg->rs); mono_bblock_add_inst (cfg->cbb, this); + mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE); } if (vt_reg != -1) { @@ -4215,26 +3819,28 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re MONO_INST_NEW (cfg, vtarg, OP_SETREG); vtarg->type = STACK_MP; vtarg->sreg1 = vt_reg; - vtarg->dreg = ppc_r3; + vtarg->dreg = mono_regstate_next_int (cfg->rs); mono_bblock_add_inst (cfg->cbb, vtarg); + mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE); } } MonoInst* mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - /* MonoInst *ins = NULL; - if (cmethod->klass == mono_defaults.math_class) { + if (cmethod->klass == mono_defaults.thread_class && + strcmp (cmethod->name, "MemoryBarrier") == 0) { + MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER); + } + /*if (cmethod->klass == mono_defaults.math_class) { if (strcmp (cmethod->name, "Sqrt") == 0) { MONO_INST_NEW (cfg, ins, OP_SQRT); ins->inst_i0 = args [0]; } - } + }*/ return ins; - */ - return NULL; } gboolean