X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-sparc.c;h=e44f8ffdb579bc89458cdd7e86df65b082c06225;hb=8bbbe2cc843eba97704e18e8ace5a102ddc0132d;hp=67b0cdd797321169b9ba9ed167795b9c623fe9e7;hpb=58790934937528970d49ef41bee58d5e40c9c6c1;p=mono.git diff --git a/mono/mini/mini-sparc.c b/mono/mini/mini-sparc.c index 67b0cdd7973..e44f8ffdb57 100644 --- a/mono/mini/mini-sparc.c +++ b/mono/mini/mini-sparc.c @@ -31,10 +31,10 @@ #include #include "mini-sparc.h" -#include "inssel.h" #include "trace.h" #include "cpu-sparc.h" #include "jit-icalls.h" +#include "ir-emit.h" /* * Sparc V9 means two things: @@ -162,9 +162,6 @@ static gboolean v64 = FALSE; static gpointer mono_arch_get_lmf_addr (void); -static int -mono_spillvar_offset_float (MonoCompile *cfg, int spillvar); - const char* mono_arch_regname (int reg) { static const char * rnames[] = { @@ -791,8 +788,9 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv) * Set var information according to the calling convention. sparc version. * The locals var stuff should most likely be split in another method. */ + void -mono_arch_allocate_vars (MonoCompile *m) +mono_arch_allocate_vars (MonoCompile *cfg) { MonoMethodSignature *sig; MonoMethodHeader *header; @@ -800,34 +798,46 @@ mono_arch_allocate_vars (MonoCompile *m) int i, offset, size, align, curinst; CallInfo *cinfo; - header = mono_method_get_header (m->method); + header = mono_method_get_header (cfg->method); - sig = mono_method_signature (m->method); + sig = mono_method_signature (cfg->method); - cinfo = get_call_info (m, sig, FALSE); + cinfo = get_call_info (cfg, sig, FALSE); if (sig->ret->type != MONO_TYPE_VOID) { switch (cinfo->ret.storage) { case ArgInIReg: case ArgInFReg: + cfg->ret->opcode = OP_REGVAR; + cfg->ret->inst_c0 = cinfo->ret.reg; + break; case ArgInIRegPair: - m->ret->opcode = OP_REGVAR; - m->ret->inst_c0 = cinfo->ret.reg; + if (((sig->ret->type == MONO_TYPE_I8) || (sig->ret->type == MONO_TYPE_U8))) { + MonoInst *low = get_vreg_to_inst (cfg, cfg->ret->dreg + 1); + MonoInst *high = get_vreg_to_inst (cfg, cfg->ret->dreg + 2); + + low->opcode = OP_REGVAR; + low->dreg = cinfo->ret.reg + 1; + high->opcode = OP_REGVAR; + high->dreg = cinfo->ret.reg; + } + cfg->ret->opcode = OP_REGVAR; + cfg->ret->inst_c0 = cinfo->ret.reg; break; case ArgOnStack: #ifdef SPARCV9 g_assert_not_reached (); #else /* valuetypes */ - m->ret->opcode = OP_REGOFFSET; - m->ret->inst_basereg = sparc_fp; - m->ret->inst_offset = 64; + cfg->vret_addr->opcode = OP_REGOFFSET; + cfg->vret_addr->inst_basereg = sparc_fp; + cfg->vret_addr->inst_offset = 64; #endif break; default: NOT_IMPLEMENTED; } - m->ret->dreg = m->ret->inst_c0; + cfg->ret->dreg = cfg->ret->inst_c0; } /* @@ -837,7 +847,7 @@ mono_arch_allocate_vars (MonoCompile *m) */ /* Locals are allocated backwards from %fp */ - m->frame_reg = sparc_fp; + cfg->frame_reg = sparc_fp; offset = 0; /* @@ -847,16 +857,16 @@ mono_arch_allocate_vars (MonoCompile *m) if (header->num_clauses) offset += sizeof (gpointer) * 2; - if (m->method->save_lmf) { + if (cfg->method->save_lmf) { offset += sizeof (MonoLMF); - m->arch.lmf_offset = offset; + cfg->arch.lmf_offset = offset; } - curinst = m->locals_start; - for (i = curinst; i < m->num_varinfo; ++i) { - inst = m->varinfo [i]; + curinst = cfg->locals_start; + for (i = curinst; i < cfg->num_varinfo; ++i) { + inst = cfg->varinfo [i]; - if (inst->opcode == OP_REGVAR) { + if ((inst->opcode == OP_REGVAR) || (inst->opcode == OP_REGOFFSET)) { //g_print ("allocating local %d to %s\n", i, mono_arch_regname (inst->dreg)); continue; } @@ -869,7 +879,7 @@ mono_arch_allocate_vars (MonoCompile *m) if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) size = mono_class_native_size (inst->inst_vtype->data.klass, &align); else - size = mini_type_stack_size (m->generic_sharing_context, inst->inst_vtype, &align); + size = mini_type_stack_size (cfg->generic_sharing_context, inst->inst_vtype, &align); /* * This is needed since structures containing doubles must be doubleword @@ -895,11 +905,11 @@ mono_arch_allocate_vars (MonoCompile *m) } if (sig->call_convention == MONO_CALL_VARARG) { - m->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET; + cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET; } for (i = 0; i < sig->param_count + sig->hasthis; ++i) { - inst = m->args [i]; + inst = cfg->args [i]; if (inst->opcode != OP_REGVAR) { ArgInfo *ainfo = &cinfo->args [i]; gboolean inreg = TRUE; @@ -922,6 +932,7 @@ mono_arch_allocate_vars (MonoCompile *m) #endif /* FIXME: Allocate volatile arguments to registers */ + /* FIXME: This makes the argument holding a vtype address into volatile */ if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) inreg = FALSE; @@ -938,10 +949,22 @@ mono_arch_allocate_vars (MonoCompile *m) switch (storage) { case ArgInIReg: - case ArgInIRegPair: inst->opcode = OP_REGVAR; inst->dreg = sparc_i0 + ainfo->reg; break; + case ArgInIRegPair: + if (inst->type == STACK_I8) { + MonoInst *low = get_vreg_to_inst (cfg, inst->dreg + 1); + MonoInst *high = get_vreg_to_inst (cfg, inst->dreg + 2); + + low->opcode = OP_REGVAR; + low->dreg = sparc_i0 + ainfo->reg + 1; + high->opcode = OP_REGVAR; + high->dreg = sparc_i0 + ainfo->reg; + } + inst->opcode = OP_REGVAR; + inst->dreg = sparc_i0 + ainfo->reg; + break; case ArgInFloatReg: case ArgInDoubleReg: /* @@ -986,47 +1009,249 @@ mono_arch_allocate_vars (MonoCompile *m) * are destructively modified in a lot of places in inssel.brg. */ MonoInst *indir; - MONO_INST_NEW (m, indir, 0); + MONO_INST_NEW (cfg, indir, 0); *indir = *inst; - inst->opcode = OP_SPARC_INARG_VT; + inst->opcode = OP_VTARG_ADDR; inst->inst_left = indir; } } } + /* Add a properly aligned dword for use by int<->float conversion opcodes */ + offset += 8; + offset = ALIGN_TO (offset, 8); + cfg->arch.float_spill_slot_offset = offset; + /* * spillvars are stored between the normal locals and the storage reserved * by the ABI. */ - m->stack_offset = offset; - - /* Add a properly aligned dword for use by int<->float conversion opcodes */ - m->spill_count ++; - mono_spillvar_offset_float (m, 0); + cfg->stack_offset = offset; g_free (cinfo); } -static MonoInst * -make_group (MonoCompile *cfg, MonoInst *left, int basereg, int offset) +void +mono_arch_create_vars (MonoCompile *cfg) { - MonoInst *group; + MonoMethodSignature *sig; - MONO_INST_NEW (cfg, group, OP_GROUP); - group->inst_left = left; - group->inst_basereg = basereg; - group->inst_imm = offset; + sig = mono_method_signature (cfg->method); - return group; + if (MONO_TYPE_ISSTRUCT ((sig->ret))) { + cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG); + if (G_UNLIKELY (cfg->verbose_level > 1)) { + printf ("vret_addr = "); + mono_print_ins (cfg->vret_addr); + } + } } static void -emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) +add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, guint32 sreg) +{ + MonoInst *arg; + + MONO_INST_NEW (cfg, arg, 0); + + arg->sreg1 = sreg; + + switch (storage) { + case ArgInIReg: + arg->opcode = OP_MOVE; + arg->dreg = mono_alloc_ireg (cfg); + + mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE); + break; + case ArgInFloatReg: + arg->opcode = OP_FMOVE; + arg->dreg = mono_alloc_freg (cfg); + + mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE); + break; + default: + g_assert_not_reached (); + } + + MONO_ADD_INS (cfg->cbb, arg); +} + +static void +add_outarg_load (MonoCompile *cfg, MonoCallInst *call, int opcode, int basereg, int offset, int reg) +{ + MonoInst *arg; + int dreg = mono_alloc_ireg (cfg); + + EMIT_NEW_LOAD_MEMBASE (cfg, arg, OP_LOAD_MEMBASE, dreg, sparc_sp, offset); + MONO_ADD_INS (cfg->cbb, arg); + + mono_call_inst_add_outarg_reg (cfg, call, dreg, reg, FALSE); +} + +static void +emit_pass_long (MonoCompile *cfg, MonoCallInst *call, ArgInfo *ainfo, MonoInst *in) +{ + int offset = ARGS_OFFSET + ainfo->offset; + + switch (ainfo->storage) { + case ArgInIRegPair: + add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg + 1, in->dreg + 1); + add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, in->dreg + 2); + break; + case ArgOnStackPair: + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset, in->dreg + 2); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset + 4, in->dreg + 1); + break; + case ArgInSplitRegStack: + add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, in->dreg + 2); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset + 4, in->dreg + 1); + break; + default: + g_assert_not_reached (); + } +} + +static void +emit_pass_double (MonoCompile *cfg, MonoCallInst *call, ArgInfo *ainfo, MonoInst *in) +{ + int offset = ARGS_OFFSET + ainfo->offset; + + switch (ainfo->storage) { + case ArgInIRegPair: + /* floating-point <-> integer transfer must go through memory */ + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, sparc_sp, offset, in->dreg); + + /* Load into a register pair */ + add_outarg_load (cfg, call, OP_LOADI4_MEMBASE, sparc_sp, offset, sparc_o0 + ainfo->reg); + add_outarg_load (cfg, call, OP_LOADI4_MEMBASE, sparc_sp, offset + 4, sparc_o0 + ainfo->reg + 1); + break; + case ArgOnStackPair: + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, sparc_sp, offset, in->dreg); + break; + case ArgInSplitRegStack: + /* floating-point <-> integer transfer must go through memory */ + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, sparc_sp, offset, in->dreg); + /* Load most significant word into register */ + add_outarg_load (cfg, call, OP_LOADI4_MEMBASE, sparc_sp, offset, sparc_o0 + ainfo->reg); + break; + default: + g_assert_not_reached (); + } +} + +static void +emit_pass_float (MonoCompile *cfg, MonoCallInst *call, ArgInfo *ainfo, MonoInst *in) +{ + int offset = ARGS_OFFSET + ainfo->offset; + + switch (ainfo->storage) { + case ArgInIReg: + /* floating-point <-> integer transfer must go through memory */ + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, sparc_sp, offset, in->dreg); + add_outarg_load (cfg, call, OP_LOADI4_MEMBASE, sparc_sp, offset, sparc_o0 + ainfo->reg); + break; + case ArgOnStack: + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, sparc_sp, offset, in->dreg); + break; + default: + g_assert_not_reached (); + } +} + +static void +emit_pass_other (MonoCompile *cfg, MonoCallInst *call, ArgInfo *ainfo, MonoType *arg_type, MonoInst *in); + +static void +emit_pass_vtype (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo, ArgInfo *ainfo, MonoType *arg_type, MonoInst *in, gboolean pinvoke) { MonoInst *arg; + guint32 align, offset, pad, size; + + if (arg_type->type == MONO_TYPE_TYPEDBYREF) { + size = sizeof (MonoTypedRef); + align = sizeof (gpointer); + } + else if (pinvoke) + size = mono_type_native_stack_size (&in->klass->byval_arg, &align); + else { + /* + * Other backends use mono_type_stack_size (), but that + * aligns the size to 8, which is larger than the size of + * the source, leading to reads of invalid memory if the + * source is at the end of address space. + */ + size = mono_class_value_size (in->klass, &align); + } + + /* The first 6 argument locations are reserved */ + if (cinfo->stack_usage < 6 * sizeof (gpointer)) + cinfo->stack_usage = 6 * sizeof (gpointer); + + offset = ALIGN_TO ((ARGS_OFFSET - STACK_BIAS) + cinfo->stack_usage, align); + pad = offset - ((ARGS_OFFSET - STACK_BIAS) + cinfo->stack_usage); + + cinfo->stack_usage += size; + cinfo->stack_usage += pad; + + /* + * We use OP_OUTARG_VT to copy the valuetype to a stack location, then + * use the normal OUTARG opcodes to pass the address of the location to + * the callee. + */ + if (size > 0) { + MONO_INST_NEW (cfg, arg, OP_OUTARG_VT); + arg->sreg1 = in->dreg; + arg->klass = in->klass; + arg->backend.size = size; + arg->inst_p0 = call; + arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo)); + memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo)); + ((ArgInfo*)(arg->inst_p1))->offset = STACK_BIAS + offset; + MONO_ADD_INS (cfg->cbb, arg); + + MONO_INST_NEW (cfg, arg, OP_ADD_IMM); + arg->dreg = mono_alloc_preg (cfg); + arg->sreg1 = sparc_sp; + arg->inst_imm = STACK_BIAS + offset; + MONO_ADD_INS (cfg->cbb, arg); + + emit_pass_other (cfg, call, ainfo, NULL, arg); + } +} + +static void +emit_pass_other (MonoCompile *cfg, MonoCallInst *call, ArgInfo *ainfo, MonoType *arg_type, MonoInst *in) +{ + int offset = ARGS_OFFSET + ainfo->offset; + int opcode; + + switch (ainfo->storage) { + case ArgInIReg: + add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, in->dreg); + break; + case ArgOnStack: +#ifdef SPARCV9 + NOT_IMPLEMENTED; +#else + if (offset & 0x1) + opcode = OP_STOREI1_MEMBASE_REG; + else if (offset & 0x2) + opcode = OP_STOREI2_MEMBASE_REG; + else + opcode = OP_STOREI4_MEMBASE_REG; + MONO_EMIT_NEW_STORE_MEMBASE (cfg, opcode, sparc_sp, offset, in->dreg); +#endif + break; + default: + g_assert_not_reached (); + } +} + +static void +emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) +{ MonoMethodSignature *tmp_sig; - MonoInst *sig_arg; /* * mono_ArgIterator_Setup assumes the signature cookie is @@ -1042,24 +1267,13 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) /* FIXME: Add support for signature tokens to AOT */ cfg->disable_aot = TRUE; /* We allways pass the signature on the stack for simplicity */ - MONO_INST_NEW (cfg, arg, OP_SPARC_OUTARG_MEM); - arg->inst_right = make_group (cfg, (MonoInst*)call, sparc_sp, ARGS_OFFSET + cinfo->sig_cookie.offset); - MONO_INST_NEW (cfg, sig_arg, OP_ICONST); - sig_arg->inst_p0 = tmp_sig; - arg->inst_left = sig_arg; - arg->type = STACK_PTR; - MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args); + MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sparc_sp, ARGS_OFFSET + cinfo->sig_cookie.offset, tmp_sig); } -/* - * take the arguments and generate the arch-specific - * instructions to properly call the function in call. - * This includes pushing, moving arguments to the right register - * etc. - */ -MonoCallInst* -mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) { - MonoInst *arg, *in; +void +mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) +{ + MonoInst *in; MonoMethodSignature *sig; int i, n; CallInfo *cinfo; @@ -1071,7 +1285,14 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, cinfo = get_call_info (cfg, sig, sig->pinvoke); + if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) { + /* Set the 'struct/union return pointer' location on the stack */ + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, 64, call->vret_var->dreg); + } + for (i = 0; i < n; ++i) { + MonoType *arg_type; + ainfo = cinfo->args + i; if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) { @@ -1079,118 +1300,23 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, emit_sig_cookie (cfg, call, cinfo); } - if (is_virtual && i == 0) { - /* the argument will be attached to the call instruction */ - in = call->args [i]; - } else { - MONO_INST_NEW (cfg, arg, OP_OUTARG); - in = call->args [i]; - arg->cil_code = in->cil_code; - arg->inst_left = in; - arg->type = in->type; - MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args); - - if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) { - MonoInst *inst; - gint align; - guint32 offset, pad; - guint32 size; - -#ifdef SPARCV9 - if (sig->pinvoke) - NOT_IMPLEMENTED; -#endif - - if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) { - size = sizeof (MonoTypedRef); - align = sizeof (gpointer); - } - else - if (sig->pinvoke) - size = mono_type_native_stack_size (&in->klass->byval_arg, &align); - else { - /* - * Can't use mini_type_stack_size (), but that - * aligns the size to sizeof (gpointer), which is larger - * than the size of the source, leading to reads of invalid - * memory if the source is at the end of address space or - * misaligned reads. - */ - size = mono_class_value_size (in->klass, &align); - } - - /* - * We use OP_OUTARG_VT to copy the valuetype to a stack location, then - * use the normal OUTARG opcodes to pass the address of the location to - * the callee. - */ - MONO_INST_NEW (cfg, inst, OP_OUTARG_VT); - inst->inst_left = in; + in = call->args [i]; - /* The first 6 argument locations are reserved */ - if (cinfo->stack_usage < 6 * sizeof (gpointer)) - cinfo->stack_usage = 6 * sizeof (gpointer); - - offset = ALIGN_TO ((ARGS_OFFSET - STACK_BIAS) + cinfo->stack_usage, align); - pad = offset - ((ARGS_OFFSET - STACK_BIAS) + cinfo->stack_usage); - - inst->inst_c1 = STACK_BIAS + offset; - inst->backend.size = size; - arg->inst_left = inst; - - cinfo->stack_usage += size; - cinfo->stack_usage += pad; - } - - arg->inst_right = make_group (cfg, (MonoInst*)call, sparc_sp, ARGS_OFFSET + ainfo->offset); - - switch (ainfo->storage) { - case ArgInIReg: - case ArgInFReg: - case ArgInIRegPair: - if (ainfo->storage == ArgInIRegPair) - arg->opcode = OP_SPARC_OUTARG_REGPAIR; - arg->backend.reg3 = sparc_o0 + ainfo->reg; - call->used_iregs |= 1 << ainfo->reg; - - if ((i >= sig->hasthis) && !sig->params [i - sig->hasthis]->byref && ((sig->params [i - sig->hasthis]->type == MONO_TYPE_R8) || (sig->params [i - sig->hasthis]->type == MONO_TYPE_R4))) { - /* An fp value is passed in an ireg */ - - if (arg->opcode == OP_SPARC_OUTARG_REGPAIR) - arg->opcode = OP_SPARC_OUTARG_REGPAIR_FLOAT; - else - arg->opcode = OP_SPARC_OUTARG_FLOAT; + if (sig->hasthis && (i == 0)) + arg_type = &mono_defaults.object_class->byval_arg; + else + arg_type = sig->params [i - sig->hasthis]; - /* - * The OUTARG (freg) implementation needs an extra dword to store - * the temporary value. - */ - extra_space += 8; - } - break; - case ArgOnStack: - arg->opcode = OP_SPARC_OUTARG_MEM; - break; - case ArgOnStackPair: - arg->opcode = OP_SPARC_OUTARG_MEMPAIR; - break; - case ArgInSplitRegStack: - arg->opcode = OP_SPARC_OUTARG_SPLIT_REG_STACK; - arg->backend.reg3 = sparc_o0 + ainfo->reg; - call->used_iregs |= 1 << ainfo->reg; - break; - case ArgInFloatReg: - arg->opcode = OP_SPARC_OUTARG_FLOAT_REG; - arg->backend.reg3 = sparc_f0 + ainfo->reg; - break; - case ArgInDoubleReg: - arg->opcode = OP_SPARC_OUTARG_DOUBLE_REG; - arg->backend.reg3 = sparc_f0 + ainfo->reg; - break; - default: - NOT_IMPLEMENTED; - } - } + if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) + emit_pass_vtype (cfg, call, cinfo, ainfo, arg_type, in, sig->pinvoke); + else if (!arg_type->byref && ((arg_type->type == MONO_TYPE_I8) || (arg_type->type == MONO_TYPE_U8))) + emit_pass_long (cfg, call, ainfo, in); + else if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) + emit_pass_double (cfg, call, ainfo, in); + else if (!arg_type->byref && (arg_type->type == MONO_TYPE_R4)) + emit_pass_float (cfg, call, ainfo, in); + else + emit_pass_other (cfg, call, ainfo, arg_type, in); } /* Handle the case where there are no implicit arguments */ @@ -1199,85 +1325,66 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, } call->stack_usage = cinfo->stack_usage + extra_space; - call->out_ireg_args = NULL; - call->out_freg_args = NULL; - cfg->param_area = MAX (cfg->param_area, call->stack_usage); - cfg->flags |= MONO_CFG_HAS_CALLS; g_free (cinfo); - return call; } +void +mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) +{ + ArgInfo *ainfo = (ArgInfo*)ins->inst_p1; + int size = ins->backend.size; + + mini_emit_memcpy (cfg, sparc_sp, ainfo->offset, src->dreg, 0, size, 0); +} + +void +mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) +{ + CallInfo *cinfo = get_call_info (cfg, mono_method_signature (method), FALSE); + + switch (cinfo->ret.storage) { + case ArgInIReg: + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg); + break; + case ArgInIRegPair: + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg + 2); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg + 1, val->dreg + 1); + break; + case ArgInFReg: + if (mono_method_signature (method)->ret->type == MONO_TYPE_R4) + MONO_EMIT_NEW_UNALU (cfg, OP_SETFRET, cfg->ret->dreg, val->dreg); + else + MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg); + break; + default: + g_assert_not_reached (); + } + + g_assert (cinfo); +} + +int cond_to_sparc_cond [][3] = { + {sparc_be, sparc_be, sparc_fbe}, + {sparc_bne, sparc_bne, 0}, + {sparc_ble, sparc_ble, sparc_fble}, + {sparc_bge, sparc_bge, sparc_fbge}, + {sparc_bl, sparc_bl, sparc_fbl}, + {sparc_bg, sparc_bg, sparc_fbg}, + {sparc_bleu, sparc_bleu, 0}, + {sparc_beu, sparc_beu, 0}, + {sparc_blu, sparc_blu, sparc_fbl}, + {sparc_bgu, sparc_bgu, sparc_fbg} +}; + /* Map opcode to the sparc condition codes */ static inline SparcCond opcode_to_sparc_cond (int opcode) { + CompRelation rel; + CompType t; + switch (opcode) { - case OP_FBGE: - return sparc_fbge; - case OP_FBLE: - return sparc_fble; - case OP_FBEQ: - case OP_FCEQ: - return sparc_fbe; - case OP_FBLT: - case OP_FCLT: - case OP_FCLT_UN: - return sparc_fbl; - case OP_FBGT: - case OP_FCGT: - case OP_FCGT_UN: - return sparc_fbg; - case CEE_BEQ: - case OP_IBEQ: - case OP_CEQ: - case OP_ICEQ: - case OP_COND_EXC_EQ: - return sparc_be; - case CEE_BNE_UN: - case OP_COND_EXC_NE_UN: - case OP_IBNE_UN: - return sparc_bne; - case CEE_BLT: - case OP_IBLT: - case OP_CLT: - case OP_ICLT: - case OP_COND_EXC_LT: - return sparc_bl; - case CEE_BLT_UN: - case OP_IBLT_UN: - case OP_CLT_UN: - case OP_ICLT_UN: - case OP_COND_EXC_LT_UN: - return sparc_blu; - case CEE_BGT: - case OP_IBGT: - case OP_CGT: - case OP_ICGT: - case OP_COND_EXC_GT: - return sparc_bg; - case CEE_BGT_UN: - case OP_IBGT_UN: - case OP_CGT_UN: - case OP_ICGT_UN: - case OP_COND_EXC_GT_UN: - return sparc_bgu; - case CEE_BGE: - case OP_IBGE: - case OP_COND_EXC_GE: - return sparc_bge; - case CEE_BGE_UN: - case OP_IBGE_UN: - case OP_COND_EXC_GE_UN: - return sparc_beu; - case CEE_BLE: - case OP_IBLE: - case OP_COND_EXC_LE: - return sparc_ble; - case CEE_BLE_UN: - case OP_IBLE_UN: - case OP_COND_EXC_LE_UN: - return sparc_bleu; case OP_COND_EXC_OV: case OP_COND_EXC_IOV: return sparc_bvs; @@ -1288,9 +1395,14 @@ opcode_to_sparc_cond (int opcode) case OP_COND_EXC_NC: NOT_IMPLEMENTED; default: - g_assert_not_reached (); - return sparc_be; + rel = mono_opcode_to_cond (opcode); + t = mono_opcode_to_type (opcode, -1); + + return cond_to_sparc_cond [rel][t]; + break; } + + return -1; } #define COMPUTE_DISP(ins) \ @@ -1482,14 +1594,18 @@ emit_call (MonoCompile *cfg, guint32 *code, guint32 patch_type, gconstpointer da return code; } -static void -peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) +void +mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoInst *ins, *n; +} - MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) { - MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list); +void +mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) +{ + MonoInst *ins, *n, *last_ins = NULL; + ins = bb->code; + MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) { switch (ins->opcode) { case OP_MUL_IMM: /* remove unnecessary multiplication with 1 */ @@ -1497,7 +1613,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) if (ins->dreg != ins->sreg1) { ins->opcode = OP_MOVE; } else { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } } @@ -1514,7 +1630,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { if (ins->dreg == last_ins->sreg1) { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } else { //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); @@ -1537,7 +1653,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_offset == last_ins->inst_offset) { if (ins->dreg == last_ins->dreg) { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } else { ins->opcode = OP_MOVE; @@ -1571,7 +1687,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { if (ins->dreg == last_ins->sreg1) { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } else { //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); @@ -1585,7 +1701,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { if (ins->dreg == last_ins->sreg1) { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } else { //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); @@ -1609,17 +1725,17 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) if (sparcv9) { last_ins->opcode = OP_STOREI8_MEMBASE_IMM; last_ins->inst_offset = ins->inst_offset; - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } } break; - case CEE_BEQ: - case CEE_BNE_UN: - case CEE_BLT: - case CEE_BGT: - case CEE_BGE: - case CEE_BLE: + case OP_IBEQ: + case OP_IBNE_UN: + case OP_IBLT: + case OP_IBGT: + case OP_IBGE: + case OP_IBLE: case OP_COND_EXC_EQ: case OP_COND_EXC_GE: case OP_COND_EXC_GT: @@ -1639,22 +1755,22 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) (last_ins->opcode == OP_COMPARE_IMM) && (last_ins->inst_imm == 0)) { switch (ins->opcode) { - case CEE_BEQ: + case OP_IBEQ: ins->opcode = OP_SPARC_BRZ; break; - case CEE_BNE_UN: + case OP_IBNE_UN: ins->opcode = OP_SPARC_BRNZ; break; - case CEE_BLT: + case OP_IBLT: ins->opcode = OP_SPARC_BRLZ; break; - case CEE_BGT: + case OP_IBGT: ins->opcode = OP_SPARC_BRGZ; break; - case CEE_BGE: + case OP_IBGE: ins->opcode = OP_SPARC_BRGEZ; break; - case CEE_BLE: + case OP_IBLE: ins->opcode = OP_SPARC_BRLEZ; break; case OP_COND_EXC_EQ: @@ -1678,28 +1794,18 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) default: g_assert_not_reached (); } - last_ins->data = ins->data; - last_ins->opcode = ins->opcode; - last_ins->type = ins->type; - last_ins->ssa_op = ins->ssa_op; - last_ins->flags = ins->flags; - last_ins->dreg = ins->dreg; - last_ins->sreg2 = ins->sreg2; - last_ins->backend = ins->backend; - last_ins->klass = ins->klass; - last_ins->cil_code = ins->cil_code; - MONO_DEL_INS (ins); + ins->sreg1 = last_ins->sreg1; + *last_ins = *ins; + MONO_DELETE_INS (bb, ins); continue; } break; - case CEE_CONV_I4: - case CEE_CONV_U4: case OP_MOVE: /* * OP_MOVE reg, reg */ if (ins->dreg == ins->sreg1) { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } /* @@ -1709,41 +1815,24 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) if (last_ins && last_ins->opcode == OP_MOVE && ins->sreg1 == last_ins->dreg && ins->dreg == last_ins->sreg1) { - MONO_DEL_INS (ins); + MONO_DELETE_INS (bb, ins); continue; } break; } + last_ins = ins; + ins = ins->next; } + bb->last_ins = last_ins; } -static int -mono_spillvar_offset_float (MonoCompile *cfg, int spillvar) +void +mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoSpillInfo **si, *info; - - g_assert (spillvar == 0); - - si = &cfg->spill_info_float; - - if (!*si) { - *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo)); - cfg->stack_offset += sizeof (double); - cfg->stack_offset = ALIGN_TO (cfg->stack_offset, 8); - info->offset = - cfg->stack_offset; - } - - return MONO_SPARC_STACK_BIAS + (*si)->offset; } /* FIXME: Strange loads from the stack in basic-float.cs:test_2_rem */ -void -mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) -{ - mono_local_regalloc (cfg, bb); -} - static void sparc_patch (guint32 *code, const gpointer target) { @@ -1947,7 +2036,7 @@ emit_move_return_value (MonoInst *ins, guint32 *code) case OP_VOIDCALL_REG: case OP_VOIDCALL_MEMBASE: break; - case CEE_CALL: + case OP_CALL: case OP_CALL_REG: case OP_CALL_MEMBASE: g_assert (ins->dreg == sparc_o0); @@ -1986,6 +2075,9 @@ emit_move_return_value (MonoInst *ins, guint32 *code) case OP_VCALL: case OP_VCALL_REG: case OP_VCALL_MEMBASE: + case OP_VCALL2: + case OP_VCALL2_REG: + case OP_VCALL2_MEMBASE: break; default: NOT_IMPLEMENTED; @@ -2021,6 +2113,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint32 *code) ArgInfo *ainfo = cinfo->args + i; gint32 stack_offset; MonoType *arg_type; + inst = cfg->args [i]; if (sig->hasthis && (i == 0)) @@ -2245,12 +2338,15 @@ mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs) * LOCKING: called with the domain lock held */ gpointer -mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count) +mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, + gpointer fail_tramp) { int i; int size = 0; guint32 *code, *start; + g_assert (!fail_tramp); + for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; if (item->is_equals) { @@ -2270,7 +2366,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI } size += item->chunk_size; } - code = mono_code_manager_reserve (domain->code_mp, size * 4); + code = mono_domain_code_reserve (domain, size * 4); start = code; for (i = 0; i < count; ++i) { @@ -2279,13 +2375,13 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI if (item->is_equals) { if (item->check_target_idx) { if (!item->compare_done) { - sparc_set (code, (guint32)item->method, sparc_g5); + sparc_set (code, (guint32)item->key, sparc_g5); sparc_cmp (code, MONO_ARCH_IMT_REG, sparc_g5); } item->jmp_code = (guint8*)code; sparc_branch (code, 0, sparc_bne, 0); sparc_nop (code); - sparc_set (code, ((guint32)(&(vtable->vtable [item->vtable_slot]))), sparc_g5); + sparc_set (code, ((guint32)(&(vtable->vtable [item->value.vtable_slot]))), sparc_g5); sparc_ld (code, sparc_g5, 0, sparc_g5); sparc_jmpl (code, sparc_g5, sparc_g0, sparc_g0); sparc_nop (code); @@ -2294,7 +2390,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI #if ENABLE_WRONG_METHOD_CHECK g_assert_not_reached (); #endif - sparc_set (code, ((guint32)(&(vtable->vtable [item->vtable_slot]))), sparc_g5); + sparc_set (code, ((guint32)(&(vtable->vtable [item->value.vtable_slot]))), sparc_g5); sparc_ld (code, sparc_g5, 0, sparc_g5); sparc_jmpl (code, sparc_g5, sparc_g0, sparc_g0); sparc_nop (code); @@ -2303,7 +2399,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI #endif } } else { - sparc_set (code, (guint32)item->method, sparc_g5); + sparc_set (code, (guint32)item->key, sparc_g5); sparc_cmp (code, MONO_ARCH_IMT_REG, sparc_g5); item->jmp_code = (guint8*)code; sparc_branch (code, 0, sparc_beu, 0); @@ -2338,7 +2434,7 @@ mono_arch_find_imt_method (gpointer *regs, guint8 *code) } MonoObject* -mono_arch_find_this_argument (gpointer *regs, MonoMethod *method) +mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx) { mono_sparc_flushw (); @@ -2358,12 +2454,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) MonoCallInst *call; guint offset; guint32 *code = (guint32*)(cfg->native_code + cfg->code_len); + MonoInst *last_ins = NULL; int max_len, cpos; const char *spec; - if (cfg->opt & MONO_OPT_PEEPHOLE) - peephole_pass (cfg, bb); - if (cfg->verbose_level > 2) g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset); @@ -2435,23 +2529,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_STORE_MEMBASE_REG: EMIT_STORE_MEMBASE_REG (ins, sti); break; - case CEE_LDIND_I: -#ifdef SPARCV9 - sparc_ldx (code, ins->inst_c0, sparc_g0, ins->dreg); -#else - sparc_ld (code, ins->inst_c0, sparc_g0, ins->dreg); -#endif - break; - case CEE_LDIND_I4: -#ifdef SPARCV9 - sparc_ldsw (code, ins->inst_c0, sparc_g0, ins->dreg); -#else - sparc_ld (code, ins->inst_c0, sparc_g0, ins->dreg); -#endif - break; - case CEE_LDIND_U4: - sparc_ld (code, ins->inst_c0, sparc_g0, ins->dreg); - break; case OP_LOADU4_MEM: sparc_set (code, ins->inst_c0, ins->dreg); sparc_ld (code, ins->dreg, sparc_g0, ins->dreg); @@ -2490,22 +2567,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_LOAD_MEMBASE (ins, ldx); break; #endif - case CEE_CONV_I1: + case OP_ICONV_TO_I1: sparc_sll_imm (code, ins->sreg1, 24, sparc_o7); sparc_sra_imm (code, sparc_o7, 24, ins->dreg); break; - case CEE_CONV_I2: + case OP_ICONV_TO_I2: sparc_sll_imm (code, ins->sreg1, 16, sparc_o7); sparc_sra_imm (code, sparc_o7, 16, ins->dreg); break; - case CEE_CONV_U1: + case OP_ICONV_TO_U1: sparc_and_imm (code, FALSE, ins->sreg1, 0xff, ins->dreg); break; - case CEE_CONV_U2: + case OP_ICONV_TO_U2: sparc_sll_imm (code, ins->sreg1, 16, sparc_o7); sparc_srl_imm (code, sparc_o7, 16, ins->dreg); break; - case CEE_CONV_OVF_U4: + case OP_LCONV_TO_OVF_U4: + case OP_ICONV_TO_OVF_U4: /* Only used on V9 */ sparc_cmp_imm (code, ins->sreg1, 0); mono_add_patch_info (cfg, (guint8*)(code) - (cfg)->native_code, @@ -2521,20 +2599,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_nop (code); sparc_mov_reg_reg (code, ins->sreg1, ins->dreg); break; - case CEE_CONV_OVF_I4_UN: + case OP_LCONV_TO_OVF_I4_UN: + case OP_ICONV_TO_OVF_I4_UN: /* Only used on V9 */ NOT_IMPLEMENTED; break; - case CEE_CONV_U: - case CEE_CONV_U8: - /* Only used on V9 */ - sparc_srl_imm (code, ins->sreg1, 0, ins->dreg); - break; - case CEE_CONV_I: - case CEE_CONV_I8: - /* Only used on V9 */ - sparc_sra_imm (code, ins->sreg1, 0, ins->dreg); - break; case OP_COMPARE: case OP_LCOMPARE: case OP_ICOMPARE: @@ -2563,7 +2632,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IADDCC: sparc_add (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg); break; - case CEE_ADD: case OP_IADD: sparc_add (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2586,7 +2654,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_ISUBCC: sparc_sub (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg); break; - case CEE_SUB: case OP_ISUB: sparc_sub (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2605,7 +2672,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_ISBB_IMM: EMIT_ALU_IMM (ins, subx, TRUE); break; - case CEE_AND: case OP_IAND: sparc_and (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2613,7 +2679,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IAND_IMM: EMIT_ALU_IMM (ins, and, FALSE); break; - case CEE_DIV: case OP_IDIV: /* Sign extend sreg1 into %y */ sparc_sra_imm (code, ins->sreg1, 31, sparc_o7); @@ -2621,12 +2686,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_sdiv (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg); EMIT_COND_SYSTEM_EXCEPTION_GENERAL (code, sparc_boverflow, "ArithmeticException", TRUE, sparc_icc_short); break; - case CEE_DIV_UN: case OP_IDIV_UN: sparc_wry (code, sparc_g0, sparc_g0); sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; - case OP_DIV_IMM: { + case OP_DIV_IMM: + case OP_IDIV_IMM: { int i, imm; /* Transform division into a shift */ @@ -2659,7 +2724,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; } - case CEE_REM: + case OP_IDIV_UN_IMM: + sparc_wry (code, sparc_g0, sparc_g0); + EMIT_ALU_IMM (ins, udiv, FALSE); + break; case OP_IREM: /* Sign extend sreg1 into %y */ sparc_sra_imm (code, ins->sreg1, 31, sparc_o7); @@ -2669,7 +2737,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_smul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7); sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg); break; - case CEE_REM_UN: case OP_IREM_UN: sparc_wry (code, sparc_g0, sparc_g0); sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7); @@ -2694,7 +2761,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg); break; - case CEE_OR: case OP_IOR: sparc_or (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2702,7 +2768,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IOR_IMM: EMIT_ALU_IMM (ins, or, FALSE); break; - case CEE_XOR: case OP_IXOR: sparc_xor (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2710,7 +2775,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IXOR_IMM: EMIT_ALU_IMM (ins, xor, FALSE); break; - case CEE_SHL: case OP_ISHL: sparc_sll (code, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2723,7 +2787,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_sll (code, ins->sreg1, sparc_o7, ins->dreg); } break; - case CEE_SHR: case OP_ISHR: sparc_sra (code, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2745,7 +2808,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_srl (code, ins->sreg1, sparc_o7, ins->dreg); } break; - case CEE_SHR_UN: case OP_ISHR_UN: sparc_srl (code, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2782,17 +2844,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_srlx (code, ins->sreg1, sparc_o7, ins->dreg); } break; - case CEE_NOT: case OP_INOT: /* can't use sparc_not */ sparc_xnor (code, FALSE, ins->sreg1, sparc_g0, ins->dreg); break; - case CEE_NEG: case OP_INEG: /* can't use sparc_neg */ sparc_sub (code, FALSE, sparc_g0, ins->sreg1, ins->dreg); break; - case CEE_MUL: case OP_IMUL: sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg); break; @@ -2815,7 +2874,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_ALU_IMM (ins, smul, FALSE); break; } - case CEE_MUL_OVF: case OP_IMUL_OVF: sparc_smul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg); sparc_rdy (code, sparc_g1); @@ -2823,7 +2881,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_cmp (code, sparc_g1, sparc_o7); EMIT_COND_SYSTEM_EXCEPTION_GENERAL (ins, sparc_bne, "OverflowException", TRUE, sparc_icc_short); break; - case CEE_MUL_OVF_UN: case OP_IMUL_OVF_UN: sparc_umul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg); sparc_rdy (code, sparc_o7); @@ -2840,20 +2897,24 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0); sparc_set_template (code, ins->dreg); break; - case CEE_CONV_I4: - case CEE_CONV_U4: + case OP_JUMP_TABLE: + mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0); + sparc_set_template (code, ins->dreg); + break; + case OP_ICONV_TO_I4: + case OP_ICONV_TO_U4: case OP_MOVE: if (ins->sreg1 != ins->dreg) sparc_mov_reg_reg (code, ins->sreg1, ins->dreg); break; case OP_FMOVE: - /* Only used on V9 */ +#ifdef SPARCV9 if (ins->sreg1 != ins->dreg) sparc_fmovd (code, ins->sreg1, ins->dreg); - break; - case OP_SPARC_SETFREG_FLOAT: - /* Only used on V9 */ - sparc_fdtos (code, ins->sreg1, ins->dreg); +#else + sparc_fmovs (code, ins->sreg1, ins->dreg); + sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1); +#endif break; case OP_JMP: if (cfg->method->save_lmf) @@ -2878,8 +2939,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCALL: case OP_LCALL: case OP_VCALL: + case OP_VCALL2: case OP_VOIDCALL: - case CEE_CALL: + case OP_CALL: call = (MonoCallInst*)ins; g_assert (!call->virtual); code = emit_save_sp_to_lmf (cfg, code); @@ -2894,6 +2956,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCALL_REG: case OP_LCALL_REG: case OP_VCALL_REG: + case OP_VCALL2_REG: case OP_VOIDCALL_REG: case OP_CALL_REG: call = (MonoCallInst*)ins; @@ -2915,6 +2978,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCALL_MEMBASE: case OP_LCALL_MEMBASE: case OP_VCALL_MEMBASE: + case OP_VCALL2_MEMBASE: case OP_VOIDCALL_MEMBASE: case OP_CALL_MEMBASE: call = (MonoCallInst*)ins; @@ -2947,11 +3011,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) #endif } break; - case OP_OUTARG: - g_assert_not_reached (); - break; case OP_LOCALLOC: { guint32 size_reg; + gint32 offset2; #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK /* Perform stack touching */ @@ -2959,7 +3021,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) #endif /* Keep alignment */ - sparc_add_imm (code, FALSE, ins->sreg1, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->dreg); + /* Add 4 to compensate for the rounding of localloc_offset */ + sparc_add_imm (code, FALSE, ins->sreg1, 4 + MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->dreg); sparc_set (code, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1), sparc_o7); sparc_and (code, FALSE, ins->dreg, sparc_o7, ins->dreg); @@ -2977,8 +3040,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_sub (code, FALSE, sparc_sp, ins->dreg, ins->dreg); /* Keep %sp valid at all times */ sparc_mov_reg_reg (code, ins->dreg, sparc_sp); - g_assert (sparc_is_imm13 (MONO_SPARC_STACK_BIAS + cfg->arch.localloc_offset)); - sparc_add_imm (code, FALSE, ins->dreg, MONO_SPARC_STACK_BIAS + cfg->arch.localloc_offset, ins->dreg); + /* Round localloc_offset too so the result is at least 8 aligned */ + offset2 = ALIGN_TO (cfg->arch.localloc_offset, 8); + g_assert (sparc_is_imm13 (MONO_SPARC_STACK_BIAS + offset2)); + sparc_add_imm (code, FALSE, ins->dreg, MONO_SPARC_STACK_BIAS + offset2, ins->dreg); if (ins->flags & MONO_INST_INIT) { guint32 *br [3]; @@ -3005,23 +3070,28 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; } - case OP_SPARC_LOCALLOC_IMM: { - gint32 offset = ins->inst_c0; - + case OP_LOCALLOC_IMM: { + gint32 offset = ins->inst_imm; + gint32 offset2; + #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK /* Perform stack touching */ NOT_IMPLEMENTED; #endif - offset = ALIGN_TO (offset, MONO_ARCH_LOCALLOC_ALIGNMENT); + /* To compensate for the rounding of localloc_offset */ + offset += sizeof (gpointer); + offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); if (sparc_is_imm13 (offset)) sparc_sub_imm (code, FALSE, sparc_sp, offset, sparc_sp); else { sparc_set (code, offset, sparc_o7); sparc_sub (code, FALSE, sparc_sp, sparc_o7, sparc_sp); } - g_assert (sparc_is_imm13 (MONO_SPARC_STACK_BIAS + cfg->arch.localloc_offset)); - sparc_add_imm (code, FALSE, sparc_sp, MONO_SPARC_STACK_BIAS + cfg->arch.localloc_offset, ins->dreg); + /* Round localloc_offset too so the result is at least 8 aligned */ + offset2 = ALIGN_TO (cfg->arch.localloc_offset, 8); + g_assert (sparc_is_imm13 (MONO_SPARC_STACK_BIAS + offset2)); + sparc_add_imm (code, FALSE, sparc_sp, MONO_SPARC_STACK_BIAS + offset2, ins->dreg); if ((ins->flags & MONO_INST_INIT) && (offset > 0)) { guint32 *br [2]; int i; @@ -3058,10 +3128,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; } - case CEE_RET: - /* The return is done in the epilog */ - g_assert_not_reached (); - break; case OP_THROW: sparc_mov_reg_reg (code, ins->sreg1, sparc_o0); mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, @@ -3126,9 +3192,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LABEL: ins->inst_c0 = (guint8*)code - cfg->native_code; break; + case OP_RELAXED_NOP: + case OP_NOP: + case OP_DUMMY_USE: + case OP_DUMMY_STORE: + case OP_NOT_REACHED: + case OP_NOT_NULL: + break; case OP_BR: - if ((ins->inst_target_bb == bb->next_bb) && - ins->node.next == &bb->ins_list) + //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins); + if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins) break; if (ins->flags & MONO_INST_BRLABEL) { if (ins->inst_i0->inst_c0) { @@ -3205,7 +3278,25 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_COND_EXC_NO: case OP_COND_EXC_C: case OP_COND_EXC_NC: + case OP_COND_EXC_IEQ: + case OP_COND_EXC_INE_UN: + case OP_COND_EXC_ILT: + case OP_COND_EXC_ILT_UN: + case OP_COND_EXC_IGT: + case OP_COND_EXC_IGT_UN: + case OP_COND_EXC_IGE: + case OP_COND_EXC_IGE_UN: + case OP_COND_EXC_ILE: + case OP_COND_EXC_ILE_UN: + case OP_COND_EXC_IOV: + case OP_COND_EXC_INO: + case OP_COND_EXC_IC: + case OP_COND_EXC_INC: +#ifdef SPARCV9 + NOT_IMPLEMENTED; +#else EMIT_COND_SYSTEM_EXCEPTION (ins, opcode_to_sparc_cond (ins->opcode), ins->inst_p1); +#endif break; case OP_SPARC_COND_EXC_EQZ: EMIT_COND_SYSTEM_EXCEPTION_BPR (ins, brz, ins->inst_p1); @@ -3225,26 +3316,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_SPARC_COND_EXC_NEZ: EMIT_COND_SYSTEM_EXCEPTION_BPR (ins, brnz, ins->inst_p1); break; - case OP_COND_EXC_IOV: - case OP_COND_EXC_IC: - EMIT_COND_SYSTEM_EXCEPTION_GENERAL (ins, opcode_to_sparc_cond (ins->opcode), ins->inst_p1, TRUE, sparc_icc_short); - break; - case CEE_BEQ: - case CEE_BNE_UN: - case CEE_BLT: - case CEE_BLT_UN: - case CEE_BGT: - case CEE_BGT_UN: - case CEE_BGE: - case CEE_BGE_UN: - case CEE_BLE: - case CEE_BLE_UN: { - if (sparcv9) - EMIT_COND_BRANCH_PREDICTED (ins, opcode_to_sparc_cond (ins->opcode), 1, 1); - else - EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1); - break; - } case OP_IBEQ: case OP_IBNE_UN: @@ -3256,8 +3327,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IBGE_UN: case OP_IBLE: case OP_IBLE_UN: { - /* Only used on V9 */ - EMIT_COND_BRANCH_ICC (ins, opcode_to_sparc_cond (ins->opcode), 1, 1, sparc_icc_short); + if (sparcv9) + EMIT_COND_BRANCH_PREDICTED (ins, opcode_to_sparc_cond (ins->opcode), 1, 1); + else + EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1); break; } @@ -3346,16 +3419,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_fstod (code, FP_SCRATCH_REG, ins->dreg); break; } - case OP_FMOVE: -#ifdef SPARCV9 - sparc_fmovd (code, ins->sreg1, ins->dreg); -#else - sparc_fmovs (code, ins->sreg1, ins->dreg); - sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1); -#endif - break; - case CEE_CONV_R4: { - gint32 offset = mono_spillvar_offset_float (cfg, 0); + case OP_ICONV_TO_R4: { + gint32 offset = cfg->arch.float_spill_slot_offset; #ifdef SPARCV9 if (!sparc_is_imm13 (offset)) { sparc_set (code, offset, sparc_o7); @@ -3380,8 +3445,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_fstod (code, FP_SCRATCH_REG, ins->dreg); break; } - case CEE_CONV_R8: { - gint32 offset = mono_spillvar_offset_float (cfg, 0); + case OP_ICONV_TO_R8: { + gint32 offset = cfg->arch.float_spill_slot_offset; #ifdef SPARCV9 if (!sparc_is_imm13 (offset)) { sparc_set (code, offset, sparc_o7); @@ -3415,7 +3480,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) #endif case OP_FCONV_TO_I4: case OP_FCONV_TO_U4: { - gint32 offset = mono_spillvar_offset_float (cfg, 0); + gint32 offset = cfg->arch.float_spill_slot_offset; sparc_fdtoi (code, ins->sreg1, FP_SCRATCH_REG); if (!sparc_is_imm13 (offset)) { sparc_set (code, offset, sparc_o7); @@ -3446,16 +3511,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Emulated */ g_assert_not_reached (); break; - case CEE_CONV_R_UN: - /* Emulated */ - g_assert_not_reached (); + case OP_FCONV_TO_R4: + /* FIXME: Change precision ? */ +#ifdef SPARCV9 + sparc_fmovd (code, ins->sreg1, ins->dreg); +#else + sparc_fmovs (code, ins->sreg1, ins->dreg); + sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1); +#endif break; case OP_LCONV_TO_R_UN: { /* Emulated */ g_assert_not_reached (); break; } - case OP_LCONV_TO_OVF_I: { + case OP_LCONV_TO_OVF_I: + case OP_LCONV_TO_OVF_I4_2: { guint32 *br [3], *label [1]; /* @@ -3590,7 +3661,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1); break; case OP_CKFINITE: { - gint32 offset = mono_spillvar_offset_float (cfg, 0); + gint32 offset = cfg->arch.float_spill_slot_offset; if (!sparc_is_imm13 (offset)) { sparc_set (code, offset, sparc_o7); sparc_stdf (code, ins->sreg1, sparc_sp, sparc_o7); @@ -3632,6 +3703,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } cpos += max_len; + + last_ins = ins; } cfg->code_len = (guint8*)code - cfg->native_code; @@ -4112,6 +4185,12 @@ mono_arch_emit_epilog (MonoCompile *cfg) if (cfg->bb_exit->in_count == 1 && cfg->bb_exit->in_bb[0]->native_offset != cfg->bb_exit->native_offset) can_fold = 1; + /* + * FIXME: The last instruction might have a branch pointing into it like in + * int_ceq sparc_i0 <- + */ + can_fold = 0; + /* Try folding last instruction into the restore */ if (can_fold && (sparc_inst_op (code [-2]) == 0x2) && (sparc_inst_op3 (code [-2]) == 0x2) && sparc_inst_imm (code [-2]) && (sparc_inst_rd (code [-2]) == sparc_i0)) { /* or reg, imm, %i0 */ @@ -4334,53 +4413,11 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls) { } -void -mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *call, int this_reg, int this_type, int vt_reg) -{ - int this_out_reg = sparc_o0; - - if (vt_reg != -1) { -#ifdef SPARCV9 - MonoInst *ins; - MONO_INST_NEW (cfg, ins, OP_MOVE); - ins->sreg1 = vt_reg; - ins->dreg = mono_regstate_next_int (cfg->rs); - mono_bblock_add_inst (cfg->cbb, ins); - - mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, sparc_o0, FALSE); - - this_out_reg = sparc_o1; -#else - /* Set the 'struct/union return pointer' location on the stack */ - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, 64, vt_reg); -#endif - } - - /* add the this argument */ - if (this_reg != -1) { - MonoInst *this; - MONO_INST_NEW (cfg, this, OP_MOVE); - this->type = this_type; - 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 (cfg, call, this->dreg, this_out_reg, FALSE); - } -} - - MonoInst* -mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) +mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { MonoInst *ins = NULL; - if (cmethod->klass == mono_defaults.thread_class && - strcmp (cmethod->name, "MemoryBarrier") == 0) { - if (sparcv9) - MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER); - } - return ins; } @@ -4436,3 +4473,10 @@ MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg) { return NULL; } + +gpointer +mono_arch_context_get_int_reg (MonoContext *ctx, int reg) +{ + /* FIXME: implement */ + g_assert_not_reached (); +}