X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-arm.c;h=68a3e6c9aa708023cfbd4b2f811e86b98d729678;hb=dba1e96418a00b863db3565d5997314105bd8aa3;hp=8e3c470f7e4f9421e7d4661334b0a694ccdf9bdb;hpb=3f873286ee17d4944d67a7bc3f098cf9105c2ce3;p=mono.git diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 8e3c470f7e4..68a3e6c9aa7 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -17,7 +17,16 @@ #include "inssel.h" #include "cpu-arm.h" #include "trace.h" +#ifdef ARM_FPU_FPA #include "mono/arch/arm/arm-fpa-codegen.h" +#elif defined(ARM_FPU_VFP) +#include "mono/arch/arm/arm-vfp-codegen.h" +#endif + +static int v5_supported = 0; +static int thumb_supported = 0; + +static int mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount); /* * TODO: @@ -100,21 +109,46 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse arm_patch (code - 4, start_loop); return code; } - g_assert (arm_is_imm12 (doffset)); - g_assert (arm_is_imm12 (doffset + size)); - g_assert (arm_is_imm12 (soffset)); - g_assert (arm_is_imm12 (soffset + size)); - while (size >= 4) { - ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset); - ARM_STR_IMM (code, ARMREG_LR, dreg, doffset); - doffset += 4; - soffset += 4; - size -= 4; + if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) && + arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) { + while (size >= 4) { + ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset); + ARM_STR_IMM (code, ARMREG_LR, dreg, doffset); + doffset += 4; + soffset += 4; + size -= 4; + } + } else if (size) { + code = emit_big_add (code, ARMREG_R0, sreg, soffset); + code = emit_big_add (code, ARMREG_R1, dreg, doffset); + doffset = soffset = 0; + while (size >= 4) { + ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset); + ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset); + doffset += 4; + soffset += 4; + size -= 4; + } } g_assert (size == 0); return code; } +static guint8* +emit_call_reg (guint8 *code, int reg) +{ + if (v5_supported) { + ARM_BLX_REG (code, reg); + } else { + ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); + if (thumb_supported) + ARM_BX (code, reg); + else + ARM_MOV_REG_REG (code, ARMREG_PC, reg); + } + return code; +} + /* * mono_arch_get_argument_info: * @csig: a method signature @@ -189,6 +223,31 @@ guint32 mono_arch_cpu_optimizazions (guint32 *exclude_mask) { guint32 opts = 0; + char buf [512]; + char *line; + FILE *file = fopen ("/proc/cpuinfo", "r"); + if (file) { + while ((line = fgets (buf, 512, file))) { + if (strncmp (line, "Processor", 9) == 0) { + char *ver = strstr (line, "(v"); + if (ver && (ver [2] == '5' || ver [2] == '6' || ver [2] == '7')) { + v5_supported = TRUE; + } + continue; + } + if (strncmp (line, "Features", 8) == 0) { + char *th = strstr (line, "thumb"); + if (th) { + thumb_supported = TRUE; + if (v5_supported) + break; + } + continue; + } + } + fclose (file); + /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/ + } /* no arm-specific optimizations yet */ *exclude_mask = 0; @@ -214,6 +273,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; } @@ -298,6 +361,7 @@ mono_arch_flush_icache (guint8 *code, gint size) enum { RegTypeGeneral, RegTypeBase, + RegTypeBaseGen, RegTypeFP, RegTypeStructByVal, RegTypeStructByAddr @@ -335,16 +399,30 @@ add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple) ainfo->reg = *gr; } } else { - if (*gr > ARMREG_R2) { + if (*gr == ARMREG_R3 +#ifdef __ARM_EABI__ + && 0 +#endif + ) { + /* first word in r3 and the second on the stack */ + ainfo->offset = *stack_size; + ainfo->reg = ARMREG_SP; /* in the caller */ + ainfo->regtype = RegTypeBaseGen; + *stack_size += 4; + } else if (*gr > ARMREG_R3) { +#ifdef __ARM_EABI__ *stack_size += 7; *stack_size &= ~7; +#endif ainfo->offset = *stack_size; ainfo->reg = ARMREG_SP; /* in the caller */ ainfo->regtype = RegTypeBase; *stack_size += 8; } else { - /*if ((*gr) & 1) - (*gr) ++;*/ +#ifdef __ARM_EABI__ + if ((*gr) & 1) + (*gr) ++; +#endif ainfo->reg = *gr; } (*gr) ++; @@ -426,6 +504,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_TYPEDBYREF: case MONO_TYPE_VALUETYPE: { gint size; @@ -511,6 +597,12 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke) /* FIXME: cinfo->ret.reg = ???; cinfo->ret.regtype = RegTypeFP;*/ break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (sig->ret)) { + cinfo->ret.reg = ARMREG_R0; + break; + } + break; case MONO_TYPE_VALUETYPE: break; case MONO_TYPE_TYPEDBYREF: @@ -631,9 +723,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); @@ -654,7 +746,7 @@ mono_arch_allocate_vars (MonoCompile *m) curinst = 0; if (sig->hasthis) { - inst = m->varinfo [curinst]; + inst = m->args [curinst]; if (inst->opcode != OP_REGVAR) { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; @@ -669,7 +761,7 @@ mono_arch_allocate_vars (MonoCompile *m) } for (i = 0; i < sig->param_count; ++i) { - inst = m->varinfo [curinst]; + inst = m->args [curinst]; if (inst->opcode != OP_REGVAR) { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; @@ -756,13 +848,15 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, 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); if (arg->type == STACK_R8) { if (ainfo->size == 4) { +#ifndef MONO_ARCH_SOFT_FLOAT arg->opcode = OP_OUTARG_R4; +#endif } else { call->used_iregs |= 1 << (ainfo->reg + 1); } @@ -770,7 +864,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, } } else if (ainfo->regtype == RegTypeStructByAddr) { /* FIXME: where si the data allocated? */ - arg->unused = ainfo->reg; + arg->backend.reg3 = ainfo->reg; call->used_iregs |= 1 << ainfo->reg; g_assert_not_reached (); } else if (ainfo->regtype == RegTypeStructByVal) { @@ -782,13 +876,19 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, arg->opcode = OP_OUTARG_VT; /* vtsize and offset have just 12 bits of encoding in number of words */ g_assert (((ainfo->vtsize | (ainfo->offset / 4)) & 0xfffff000) == 0); - arg->unused = ainfo->reg | (ainfo->size << 4) | (ainfo->vtsize << 8) | ((ainfo->offset / 4) << 20); + arg->backend.arg_info = ainfo->reg | (ainfo->size << 4) | (ainfo->vtsize << 8) | ((ainfo->offset / 4) << 20); } else if (ainfo->regtype == RegTypeBase) { arg->opcode = OP_OUTARG_MEMBASE; - arg->unused = (ainfo->offset << 8) | ainfo->size; + arg->backend.arg_info = (ainfo->offset << 8) | ainfo->size; + } else if (ainfo->regtype == RegTypeBaseGen) { + call->used_iregs |= 1 << ARMREG_R3; + arg->opcode = OP_OUTARG_MEMBASE; + arg->backend.arg_info = (ainfo->offset << 8) | 0xff; + if (arg->type == STACK_R8) + cfg->flags |= MONO_CFG_HAS_FPOUT; } else if (ainfo->regtype == RegTypeFP) { - arg->unused = ainfo->reg; - /* FPA args are passed in int regs */ + arg->backend.reg3 = ainfo->reg; + /* FP args are passed in int regs */ call->used_iregs |= 1 << ainfo->reg; if (ainfo->size == 8) { arg->opcode = OP_OUTARG_R8; @@ -839,8 +939,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean ena code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method); ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */ code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func); - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_R2); + code = emit_call_reg (code, ARMREG_R2); return code; } @@ -871,7 +970,6 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena cfg->native_code = g_realloc (cfg->native_code, cfg->code_size); code = cfg->native_code + offset; } -handle_enum: switch (rtype) { case MONO_TYPE_VOID: /* special case string .ctor icall */ @@ -930,8 +1028,7 @@ handle_enum: code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method); code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func); - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); + code = emit_call_reg (code, ARMREG_IP); switch (save_mode) { case SAVE_TWO: @@ -1084,15 +1181,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: @@ -1100,15 +1190,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: @@ -1263,12 +1346,12 @@ map_to_reg_reg_op (int op) static void mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoInst *ins, *next, *temp, *last_ins = NULL; + MonoInst *ins, *temp, *last_ins = NULL; int rot_amount, imm8, low_imm; /* setup the virtual reg allocator */ - if (bb->max_ireg > cfg->rs->next_vireg) - cfg->rs->next_vireg = bb->max_ireg; + if (bb->max_vreg > cfg->rs->next_vreg) + cfg->rs->next_vreg = bb->max_vreg; ins = bb->code; while (ins) { @@ -1356,7 +1439,7 @@ loop_start: ins->inst_offset = low_imm; break; } - /* FPA doesn't have indexed load instructions */ + /* VFP/FPA doesn't have indexed load instructions */ g_assert_not_reached (); break; case OP_STORE_MEMBASE_REG: @@ -1394,7 +1477,7 @@ loop_start: break; } /*g_print ("fail with: %d (%d, %d)\n", ins->inst_offset, ins->inst_offset & ~0x1ff, low_imm);*/ - /* FPA doesn't have indexed store instructions */ + /* VFP/FPA doesn't have indexed store instructions */ g_assert_not_reached (); break; case OP_STORE_MEMBASE_IMM: @@ -1413,7 +1496,7 @@ loop_start: ins = ins->next; } bb->last_ins = last_ins; - bb->max_ireg = cfg->rs->next_vireg; + bb->max_vreg = cfg->rs->next_vreg; } @@ -1430,7 +1513,15 @@ static guchar* emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed) { /* sreg is a float, dreg is an integer reg */ +#ifdef ARM_FPU_FPA ARM_FIXZ (code, dreg, sreg); +#elif defined(ARM_FPU_VFP) + if (is_signed) + ARM_TOSIZD (code, ARM_VFP_F0, sreg); + else + ARM_TOUIZD (code, ARM_VFP_F0, sreg); + ARM_FMRS (code, dreg, ARM_VFP_F0); +#endif if (!is_signed) { if (size == 1) ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff); @@ -1465,7 +1556,7 @@ search_thunk_slot (void *data, int csize, int bsize, void *user_data) { guchar *code = data; guint32 *thunks = data; guint32 *endthunks = (guint32*)(code + bsize); - int i, count = 0; + int count = 0; int difflow, diffhigh; /* always ensure a call from pdata->code can reach to the thunks without further thunks */ @@ -1494,7 +1585,10 @@ search_thunk_slot (void *data, int csize, int bsize, void *user_data) { /* found a free slot instead: emit thunk */ code = (guchar*)thunks; ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); + if (thumb_supported) + ARM_BX (code, ARMREG_IP); + else + ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); thunks [2] = (guint32)pdata->target; mono_arch_flush_icache ((guchar*)thunks, 12); @@ -1540,19 +1634,37 @@ handle_thunk (int absolute, guchar *code, const guchar *target) { void arm_patch (guchar *code, const guchar *target) { - guint32 ins = *(guint32*)code; + guint32 *code32 = (void*)code; + guint32 ins = *code32; guint32 prim = (ins >> 25) & 7; - guint32 ovf; + guint32 tval = GPOINTER_TO_UINT (target); //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target); if (prim == 5) { /* 101b */ /* the diff starts 8 bytes from the branch opcode */ gint diff = target - code - 8; + gint tbits; + gint tmask = 0xffffffff; + if (tval & 1) { /* entering thumb mode */ + diff = target - 1 - code - 8; + g_assert (thumb_supported); + tbits = 0xf << 28; /* bl->blx bit pattern */ + g_assert ((ins & (1 << 24))); /* it must be a bl, not b instruction */ + /* this low bit of the displacement is moved to bit 24 in the instruction encoding */ + if (diff & 2) { + tbits |= 1 << 24; + } + tmask = ~(1 << 24); /* clear the link bit */ + /*g_print ("blx to thumb: target: %p, code: %p, diff: %d, mask: %x\n", target, code, diff, tmask);*/ + } else { + tbits = 0; + } if (diff >= 0) { if (diff <= 33554431) { diff >>= 2; ins = (ins & 0xff000000) | diff; - *(guint32*)code = ins; + ins &= tmask; + *code32 = ins | tbits; return; } } else { @@ -1560,7 +1672,8 @@ arm_patch (guchar *code, const guchar *target) if (diff >= -33554432) { diff >>= 2; ins = (ins & 0xff000000) | (diff & ~0xff000000); - *(guint32*)code = ins; + ins &= tmask; + *code32 = ins | tbits; return; } } @@ -1569,24 +1682,47 @@ arm_patch (guchar *code, const guchar *target) return; } - + /* + * The alternative call sequences looks like this: + * + * ldr ip, [pc] // loads the address constant + * b 1f // jumps around the constant + * address constant embedded in the code + * 1f: + * mov lr, pc + * mov pc, ip + * + * There are two cases for patching: + * a) at the end of method emission: in this case code points to the start + * of the call sequence + * b) during runtime patching of the call site: in this case code points + * to the mov pc, ip instruction + * + * We have to handle also the thunk jump code sequence: + * + * ldr ip, [pc] + * mov pc, ip + * address constant // execution never reaches here + */ if ((ins & 0x0ffffff0) == 0x12fff10) { /* branch and exchange: the address is constructed in a reg */ g_assert_not_reached (); } else { - guint32 ccode [3]; + guint32 ccode [4]; guint32 *tmp = ccode; - ARM_LDR_IMM (tmp, ARMREG_IP, ARMREG_PC, 0); - ARM_MOV_REG_REG (tmp, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (tmp, ARMREG_PC, ARMREG_IP); + guint8 *emit = (guint8*)tmp; + ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0); + ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC); + ARM_MOV_REG_REG (emit, ARMREG_PC, ARMREG_IP); + ARM_BX (emit, ARMREG_IP); if (ins == ccode [2]) { - tmp = (guint32*)code; - tmp [-1] = (guint32)target; + g_assert_not_reached (); // should be -2 ... + code32 [-1] = (guint32)target; return; } if (ins == ccode [0]) { - tmp = (guint32*)code; - tmp [2] = (guint32)target; + /* handles both thunk jump code and the far call sequence */ + code32 [2] = (guint32)target; return; } g_assert_not_reached (); @@ -1600,7 +1736,7 @@ arm_patch (guchar *code, const guchar *target) * to be used with the emit macros. * Return -1 otherwise. */ -int +static int mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount) { guint32 res, i; @@ -1702,7 +1838,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) while (ins) { offset = code - cfg->native_code; - max_len = ((guint8 *)arm_cpu_desc [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; @@ -1714,6 +1850,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_debug_record_line_number (cfg, ins, offset); switch (ins->opcode) { + case OP_MEMORY_BARRIER: + break; case OP_TLS_GET: g_assert_not_reached (); break; @@ -1848,10 +1986,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (imm8 >= 0); ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount); break; - case OP_X86_TEST_NULL: - g_assert_not_reached (); - break; - case CEE_BREAK: + case OP_BREAK: *(int*)code = 0xe7f001f0; *(int*)code = 0xef9f0001; code += 4; @@ -2052,12 +2187,21 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } case OP_SETFREG: case OP_FMOVE: +#ifdef ARM_FPU_FPA ARM_MVFD (code, ins->dreg, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CPYD (code, ins->dreg, ins->sreg1); +#endif break; case OP_FCONV_TO_R4: +#ifdef ARM_FPU_FPA ARM_MVFS (code, ins->dreg, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CVTD (code, ins->dreg, ins->sreg1); + ARM_CVTS (code, ins->dreg, ins->dreg); +#endif break; - case CEE_JMP: + case OP_JMP: /* * Keep in sync with mono_arch_emit_epilog */ @@ -2098,8 +2242,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_B (code, 0); *(gpointer*)code = NULL; code += 4; - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); + code = emit_call_reg (code, ARMREG_IP); } else { ARM_BL (code, 0); } @@ -2109,8 +2252,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_VCALL_REG: case OP_VOIDCALL_REG: case OP_CALL_REG: - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1); + code = emit_call_reg (code, ins->sreg1); break; case OP_FCALL_MEMBASE: case OP_LCALL_MEMBASE: @@ -2156,7 +2298,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert_not_reached (); ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_LR); break; - case CEE_THROW: { + case OP_THROW: { if (ins->sreg1 != ARMREG_R0) ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, @@ -2166,8 +2308,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_B (code, 0); *(gpointer*)code = NULL; code += 4; - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); + code = emit_call_reg (code, ARMREG_IP); } else { ARM_BL (code, 0); } @@ -2183,8 +2324,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_B (code, 0); *(gpointer*)code = NULL; code += 4; - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); + code = emit_call_reg (code, ARMREG_IP); } else { ARM_BL (code, 0); } @@ -2210,7 +2350,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); break; - case CEE_ENDFINALLY: + case OP_ENDFINALLY: if (arm_is_imm12 (ins->inst_left->inst_offset)) { ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset); } else { @@ -2227,7 +2367,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LABEL: ins->inst_c0 = code - cfg->native_code; break; - case CEE_BR: + case OP_BR: if (ins->flags & MONO_INST_BRLABEL) { /*if (ins->inst_i0->inst_c0) { ARM_B (code, 0); @@ -2272,7 +2412,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code += 4 * GPOINTER_TO_INT (ins->klass); break; case OP_CEQ: - ARM_MOV_REG_IMM8 (code, ins->dreg, 0); + ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ); break; case OP_CLT: @@ -2323,6 +2463,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; /* floating point opcodes */ +#ifdef ARM_FPU_FPA case OP_R8CONST: /* FIXME: we can optimize the imm load by dealing with part of * the displacement in LDFD (aligning to 512). @@ -2382,14 +2523,48 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case CEE_CONV_R8: ARM_FLTD (code, ins->dreg, ins->sreg1); break; - case OP_X86_FP_LOAD_I8: +#elif defined(ARM_FPU_VFP) + case OP_R8CONST: + /* FIXME: we can optimize the imm load by dealing with part of + * the displacement in LDFD (aligning to 512). + */ + code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0); + ARM_FLDD (code, ins->dreg, ARMREG_LR, 0); + break; + case OP_R4CONST: + code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0); + ARM_FLDS (code, ins->dreg, ARMREG_LR, 0); + ARM_CVTS (code, ins->dreg, ins->dreg); + break; + case OP_STORER8_MEMBASE_REG: + g_assert (arm_is_fpimm8 (ins->inst_offset)); + ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset); + break; + case OP_LOADR8_MEMBASE: + g_assert (arm_is_fpimm8 (ins->inst_offset)); + ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset); + break; + case OP_STORER4_MEMBASE_REG: + g_assert (arm_is_fpimm8 (ins->inst_offset)); + ARM_FSTS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset); + break; + case OP_LOADR4_MEMBASE: + g_assert (arm_is_fpimm8 (ins->inst_offset)); + ARM_FLDS (code, ins->dreg, ins->inst_basereg, ins->inst_offset); + break; + case CEE_CONV_R_UN: { g_assert_not_reached (); - /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);*/ break; - case OP_X86_FP_LOAD_I4: + } + case CEE_CONV_R4: + g_assert_not_reached (); + //ARM_FLTS (code, ins->dreg, ins->sreg1); + break; + case CEE_CONV_R8: g_assert_not_reached (); - /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);*/ + //ARM_FLTD (code, ins->dreg, ins->sreg1); break; +#endif case OP_FCONV_TO_I1: code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE); break; @@ -2448,6 +2623,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1); break; } +#ifdef ARM_FPU_FPA case OP_FADD: ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2); break; @@ -2462,7 +2638,24 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FNEG: ARM_MNFD (code, ins->dreg, ins->sreg1); + break; +#elif defined(ARM_FPU_VFP) + case OP_FADD: + ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2); + break; + case OP_FSUB: + ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2); + break; + case OP_FMUL: + ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2); + break; + case OP_FDIV: + ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2); break; + case OP_FNEG: + ARM_NEGD (code, ins->dreg, ins->sreg1); + break; +#endif case OP_FREM: /* emulated */ g_assert_not_reached (); @@ -2470,33 +2663,53 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCOMPARE: /* each fp compare op needs to do its own */ g_assert_not_reached (); - ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); + //ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); break; case OP_FCEQ: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); - ARM_MOV_REG_IMM8 (code, ins->dreg, 0); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif + ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ); break; case OP_FCLT: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif ARM_MOV_REG_IMM8 (code, ins->dreg, 0); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI); break; case OP_FCLT_UN: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif ARM_MOV_REG_IMM8 (code, ins->dreg, 0); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS); break; case OP_FCGT: /* swapped */ +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg2, ins->sreg1); +#endif ARM_MOV_REG_IMM8 (code, ins->dreg, 0); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI); break; case OP_FCGT_UN: /* swapped */ +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg2, ins->sreg1); +#endif ARM_MOV_REG_IMM8 (code, ins->dreg, 0); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI); ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS); @@ -2508,50 +2721,90 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) * V Unordered ARMCOND_VS */ case OP_FBEQ: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ); break; case OP_FBNE_UN: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ); break; case OP_FBLT: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */ break; case OP_FBLT_UN: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */ EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */ break; case OP_FBGT: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg2, ins->sreg1); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */ break; case OP_FBGT_UN: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg2, ins->sreg1); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */ EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */ break; case OP_FBGE: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); break; case OP_FBGE_UN: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg1, ins->sreg2); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */ - EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); + EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); break; case OP_FBLE: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg2, ins->sreg1); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */ break; case OP_FBLE_UN: +#ifdef ARM_FPU_FPA ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1); +#elif defined(ARM_FPU_VFP) + ARM_CMPD (code, ins->sreg2, ins->sreg1); +#endif EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */ - EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */ + EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); /* swapped */ break; - case CEE_CKFINITE: { + case OP_CKFINITE: { /*ppc_stfd (code, ins->sreg1, -8, ppc_sp); ppc_lwz (code, ppc_r11, -8, ppc_sp); ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31); @@ -2604,7 +2857,6 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono const unsigned char *target; if (patch_info->type == MONO_PATCH_INFO_SWITCH) { - gpointer *table = (gpointer *)patch_info->data.table->table; gpointer *jt = (gpointer*)(ip + 8); int i; /* jt is the inlined jump table, 2 instructions after ip @@ -2753,7 +3005,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) max_offset += 6; while (ins) { - max_offset += ((guint8 *)arm_cpu_desc [ins->opcode])[MONO_INST_LEN]; + max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; ins = ins->next; } } @@ -2771,7 +3023,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) } for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; - inst = cfg->varinfo [pos]; + inst = cfg->args [pos]; if (cfg->verbose_level > 2) g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype); @@ -2801,8 +3053,13 @@ mono_arch_emit_prolog (MonoCompile *cfg) } break; case 2: - g_assert (arm_is_imm8 (inst->inst_offset)); - ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset); + if (arm_is_imm8 (inst->inst_offset)) { + ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset); + } else { + code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset); + ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg); + ARM_STRH_IMM (code, ainfo->reg, ARMREG_IP, 0); + } break; case 8: g_assert (arm_is_imm12 (inst->inst_offset)); @@ -2819,6 +3076,12 @@ mono_arch_emit_prolog (MonoCompile *cfg) } break; } + } else if (ainfo->regtype == RegTypeBaseGen) { + g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset)); + g_assert (arm_is_imm12 (inst->inst_offset)); + ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset)); + ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4); + ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset); } else if (ainfo->regtype == RegTypeBase) { g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset)); switch (ainfo->size) { @@ -2829,8 +3092,13 @@ mono_arch_emit_prolog (MonoCompile *cfg) break; case 2: ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset)); - g_assert (arm_is_imm8 (inst->inst_offset)); - ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset); + if (arm_is_imm8 (inst->inst_offset)) { + ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset); + } else { + code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset); + ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg); + ARM_STRH_IMM (code, ARMREG_LR, ARMREG_IP, 0); + } break; case 8: g_assert (arm_is_imm12 (inst->inst_offset)); @@ -2886,8 +3154,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) ARM_B (code, 0); *(gpointer*)code = NULL; code += 4; - ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); - ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); + code = emit_call_reg (code, ARMREG_IP); } else { ARM_BL (code, 0); } @@ -2908,7 +3175,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* *(lmf_addr) = r1 */ ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); /* save method info */ - code = mono_arm_emit_load_imm (code, ARMREG_R2, method); + code = mono_arm_emit_load_imm (code, ARMREG_R2, GPOINTER_TO_INT (method)); ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method)); ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp)); /* save the current IP */ @@ -2929,7 +3196,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) void mono_arch_emit_epilog (MonoCompile *cfg) { - MonoJumpInfo *patch_info; MonoMethod *method = cfg->method; int pos, i, rot_amount; int max_epilog_size = 16 + 20*4; @@ -2951,7 +3217,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) } /* - * Keep in sync with CEE_JMP + * Keep in sync with OP_JMP */ code = cfg->native_code + cfg->code_len; @@ -2987,6 +3253,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage); ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP); } + /* FIXME: add v4 thumb interworking support */ ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC))); } @@ -3015,18 +3282,17 @@ 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 -1; } void mono_arch_emit_exceptions (MonoCompile *cfg) { MonoJumpInfo *patch_info; - int nthrows, i; + int i; guint8 *code; const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL}; guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0}; - guint32 code_size; - int exc_count = 0; int max_epilog_size = 50; /* count the number of exception infos */ @@ -3077,7 +3343,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) patch_info->data.name = "mono_arch_throw_exception_by_name"; patch_info->ip.i = code - cfg->native_code; ARM_B (code, 0); - *(gpointer*)code = ex_name; + *(gconstpointer*)code = ex_name; code += 4; break; } @@ -3120,7 +3386,7 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re this->sreg1 = this_reg; this->dreg = mono_regstate_next_int (cfg->rs); mono_bblock_add_inst (cfg->cbb, this); - mono_call_inst_add_outarg_reg (inst, this->dreg, this_dreg, FALSE); + mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE); } if (vt_reg != -1) { @@ -3130,14 +3396,19 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re vtarg->sreg1 = vt_reg; vtarg->dreg = mono_regstate_next_int (cfg->rs); mono_bblock_add_inst (cfg->cbb, vtarg); - mono_call_inst_add_outarg_reg (inst, vtarg->dreg, ARMREG_R0, FALSE); + mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ARMREG_R0, FALSE); } } MonoInst* mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - return NULL; + MonoInst *ins = NULL; + if (cmethod->klass == mono_defaults.thread_class && + strcmp (cmethod->name, "MemoryBarrier") == 0) { + MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER); + } + return ins; } gboolean