Merge pull request #444 from knocte/xbuild_improvements
[mono.git] / mono / mini / mini-ia64.c
index 556118dd14688281df38ff2b4fea6d7c3a0e54e6..c45305e2668a99e960a45797daec97f6011df4a3 100644 (file)
@@ -28,9 +28,6 @@
 #include "jit-icalls.h"
 #include "ir-emit.h"
 
-static gint appdomain_tls_offset = -1;
-static gint thread_tls_offset = -1;
-
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
 
 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
@@ -112,33 +109,11 @@ mono_arch_fregname (int reg)
                return "unknown";
 }
 
-G_GNUC_UNUSED static void
-break_count (void)
-{
-}
-
-G_GNUC_UNUSED static gboolean
-debug_count (void)
-{
-       static int count = 0;
-       count ++;
-
-       if (count == atoi (getenv ("COUNT"))) {
-               break_count ();
-       }
-
-       if (count > atoi (getenv ("COUNT"))) {
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
 static gboolean
 debug_ins_sched (void)
 {
 #if 0
-       return debug_count ();
+       return mono_debug_count ();
 #else
        return TRUE;
 #endif
@@ -148,7 +123,7 @@ static gboolean
 debug_omit_fp (void)
 {
 #if 0
-       return debug_count ();
+       return mono_debug_count ();
 #else
        return TRUE;
 #endif
@@ -191,6 +166,9 @@ typedef struct {
        guint32 reg_usage;
        guint32 freg_usage;
        gboolean need_stack_align;
+       gboolean vtype_retaddr;
+       /* The index of the vret arg in the argument list */
+       int vret_arg_index;
        ArgInfo ret;
        ArgInfo sig_cookie;
        ArgInfo args [1];
@@ -353,7 +331,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
 static CallInfo*
 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
 {
-       guint32 i, gr, fr;
+       guint32 i, gr, fr, pstart;
        MonoType *ret_type;
        int n = sig->hasthis + sig->param_count;
        guint32 stack_size = 0;
@@ -404,7 +382,7 @@ get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboo
                        cinfo->ret.reg = 8;
                        break;
                case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
+                       if (!mono_type_generic_inst_is_valuetype (ret_type)) {
                                cinfo->ret.storage = ArgInIReg;
                                cinfo->ret.reg = IA64_R8;
                                break;
@@ -419,11 +397,10 @@ get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboo
                                cinfo->ret.storage = ArgInIReg;
                        } else {
                                add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
-                               if (cinfo->ret.storage == ArgOnStack)
+                               if (cinfo->ret.storage == ArgOnStack) {
                                        /* The caller passes the address where the value is stored */
-                                       add_general (&gr, &stack_size, &cinfo->ret);
-                               if (cinfo->ret.storage == ArgInIReg)
-                                       cinfo->ret.storage = ArgValuetypeAddrInIReg;
+                                       cinfo->vtype_retaddr = TRUE;
+                               }
                        }
                        break;
                }
@@ -435,9 +412,36 @@ get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboo
                }
        }
 
-       /* this */
-       if (sig->hasthis)
-               add_general (&gr, &stack_size, cinfo->args + 0);
+       pstart = 0;
+       /*
+        * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
+        * the first argument, allowing 'this' to be always passed in the first arg reg.
+        * Also do this if the first argument is a reference type, since virtual calls
+        * are sometimes made using calli without sig->hasthis set, like in the delegate
+        * invoke wrappers.
+        */
+       if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
+               if (sig->hasthis) {
+                       add_general (&gr, &stack_size, cinfo->args + 0);
+               } else {
+                       add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
+                       pstart = 1;
+               }
+               add_general (&gr, &stack_size, &cinfo->ret);
+               if (cinfo->ret.storage == ArgInIReg)
+                       cinfo->ret.storage = ArgValuetypeAddrInIReg;
+               cinfo->vret_arg_index = 1;
+       } else {
+               /* this */
+               if (sig->hasthis)
+                       add_general (&gr, &stack_size, cinfo->args + 0);
+
+               if (cinfo->vtype_retaddr) {
+                       add_general (&gr, &stack_size, &cinfo->ret);
+                       if (cinfo->ret.storage == ArgInIReg)
+                               cinfo->ret.storage = ArgValuetypeAddrInIReg;
+               }
+       }
 
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
                gr = PARAM_REGS;
@@ -447,7 +451,7 @@ get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboo
                add_general (&gr, &stack_size, &cinfo->sig_cookie);
        }
 
-       for (i = 0; i < sig->param_count; ++i) {
+       for (i = pstart; i < sig->param_count; ++i) {
                ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
                MonoType *ptype;
 
@@ -497,7 +501,7 @@ get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboo
                        add_general (&gr, &stack_size, ainfo);
                        break;
                case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
+                       if (!mono_type_generic_inst_is_valuetype (ptype)) {
                                add_general (&gr, &stack_size, ainfo);
                                break;
                        }
@@ -549,7 +553,7 @@ get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboo
  * Returns the size of the argument area on the stack.
  */
 int
-mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
+mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
 {
        int k;
        CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
@@ -599,13 +603,26 @@ mono_arch_cleanup (void)
  * This function returns the optimizations supported on this cpu.
  */
 guint32
-mono_arch_cpu_optimizazions (guint32 *exclude_mask)
+mono_arch_cpu_optimizations (guint32 *exclude_mask)
 {
        *exclude_mask = 0;
 
        return 0;
 }
 
+/*
+ * This function test for all SIMD functions supported.
+ *
+ * Returns a bitmask corresponding to all supported versions.
+ *
+ */
+guint32
+mono_arch_cpu_enumerate_simd_versions (void)
+{
+       /* SIMD is currently unimplemented */
+       return 0;
+}
+
 GList *
 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
 {
@@ -615,7 +632,7 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
        MonoMethodHeader *header;
        CallInfo *cinfo;
 
-       header = mono_method_get_header (cfg->method);
+       header = cfg->header;
 
        sig = mono_method_signature (cfg->method);
 
@@ -673,7 +690,7 @@ mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
 
        cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
 
-       header = mono_method_get_header (cfg->method);
+       header = cfg->header;
        
        /* Some registers are reserved for use by the prolog/epilog */
        reserved_regs = header->num_clauses ? 4 : 3;
@@ -759,7 +776,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        gint32 *offsets;
        CallInfo *cinfo;
 
-       header = mono_method_get_header (cfg->method);
+       header = cfg->header;
 
        sig = mono_method_signature (cfg->method);
 
@@ -849,7 +866,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        }
 
        /* Allocate locals */
-       offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
+       offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
        if (locals_stack_align) {
                offset = ALIGN_TO (offset, locals_stack_align);
        }
@@ -1594,7 +1611,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        /* Branch opts can eliminate the branch */
                        if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
-                               ins->opcode = OP_NOP;
+                               NULLIFY_INS (ins);
                                break;
                        }
 
@@ -1630,8 +1647,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        if (MONO_IS_COND_BRANCH_OP (next)) {
                                next->opcode = OP_IA64_BR_COND;
-                               if (! (next->flags & MONO_INST_BRLABEL))
-                                       next->inst_target_bb = next->inst_true_bb;
+                               next->inst_target_bb = next->inst_true_bb;
                        } else if (MONO_IS_COND_EXC (next)) {
                                next->opcode = OP_IA64_COND_EXC;
                        } else if (MONO_IS_SETCC (next)) {
@@ -1653,7 +1669,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        /* Branch opts can eliminate the branch */
                        if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
-                               ins->opcode = OP_NOP;
+                               NULLIFY_INS (ins);
                                break;
                        }
 
@@ -1661,8 +1677,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        if (MONO_IS_COND_BRANCH_OP (next)) {
                                next->opcode = OP_IA64_BR_COND;
-                               if (! (next->flags & MONO_INST_BRLABEL))
-                                       next->inst_target_bb = next->inst_true_bb;
+                               next->inst_target_bb = next->inst_true_bb;
                        } else if (MONO_IS_COND_EXC (next)) {
                                next->opcode = OP_IA64_COND_EXC;
                        } else if (MONO_IS_SETCC (next)) {
@@ -1685,6 +1700,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        temp->sreg2 = ins->sreg2;
                        
                        ins->opcode = OP_IA64_CSET;
+                       MONO_INST_NULLIFY_SREGS (ins);
                        break;
                case OP_MUL_IMM:
                case OP_LMUL_IMM:
@@ -2045,7 +2061,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        cfg->code_size *= 2;
                        cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
                        code_start = cfg->native_code + offset;
-                       mono_jit_stats.code_reallocs++;
+                       cfg->stat_code_reallocs++;
 
                        ia64_codegen_init (code, code_start);
                }
@@ -2072,25 +2088,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        int pred = 0;
                        if (ins->opcode == OP_IA64_BR_COND)
                                pred = 6;
-                       if (ins->flags & MONO_INST_BRLABEL) {
-                               if (ins->inst_i0->inst_c0) {
-                                       NOT_IMPLEMENTED;
-                               } else {
-                                       add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
-                                       ia64_br_cond_pred (code, pred, 0);
-                               }
-                       } else {
-                               if (ins->inst_target_bb->native_offset) {
-                                       guint8 *pos = code.buf + code.nins;
+                       if (ins->inst_target_bb->native_offset) {
+                               guint8 *pos = code.buf + code.nins;
 
-                                       ia64_br_cond_pred (code, pred, 0);
-                                       ia64_begin_bundle (code);
-                                       ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
-                               } else {
-                                       add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
-                                       ia64_br_cond_pred (code, pred, 0);
-                               } 
-                       }
+                               ia64_br_cond_pred (code, pred, 0);
+                               ia64_begin_bundle (code);
+                               ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
+                       } else {
+                               add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
+                               ia64_br_cond_pred (code, pred, 0);
+                       } 
                        break;
                }
                case OP_LABEL:
@@ -2141,6 +2148,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_ISHR:
+                       ia64_sxt4 (code, GP_SCRATCH_REG, ins->sreg1);
+                       ia64_shr (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
+                       break;
                case OP_LSHR:
                        ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
@@ -2240,10 +2250,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
                        break;
                case OP_SHR_IMM:
-               case OP_ISHR_IMM:
                case OP_LSHR_IMM:
                        ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
                        break;
+               case OP_ISHR_IMM:
+                       g_assert (ins->inst_imm <= 64);
+                       ia64_extr (code, ins->dreg, ins->sreg1, ins->inst_imm, 32 - ins->inst_imm);
+                       break;
                case OP_ISHR_UN_IMM:
                        ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
                        ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
@@ -2693,7 +2706,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                /* Calls */
                case OP_CHECK_THIS:
                        /* ensure ins->sreg1 is not NULL */
-                       ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
+                       /* Can't use ld8 as this could be a vtype address */
+                       ia64_ld1 (code, GP_SCRATCH_REG, ins->sreg1);
                        break;
                case OP_ARGLIST:
                        ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
@@ -2726,13 +2740,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        int out_reg;
 
                        /* 
-                        * mono_arch_find_this_arg () needs to find the this argument in a global 
+                        * mono_arch_get_this_arg_from_call () needs to find the this argument in a global 
                         * register.
                         */
                        cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
                        out_reg = cfg->arch.reg_out0;
-                       if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
-                               out_reg ++;
                        ia64_mov (code, IA64_R10, out_reg);
 
                        /* Indirect call */
@@ -2755,12 +2767,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        CallInfo *cinfo;
                        int out_reg;
 
-                       /* 
-                        * There are no membase instructions on ia64, but we can't 
-                        * lower this since get_vcall_slot_addr () needs to decode it.
-                        */
-
-                       /* Keep this in synch with get_vcall_slot_addr */
                        ia64_mov (code, IA64_R11, ins->sreg1);
                        if (ia64_is_imm14 (ins->inst_offset))
                                ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
@@ -2784,27 +2790,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                         */
                        cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
                        out_reg = cfg->arch.reg_out0;
-                       if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
-                               out_reg ++;
                        ia64_mov (code, IA64_R10, out_reg);
 
-                       ia64_begin_bundle (code);
-                       ia64_codegen_set_one_ins_per_bundle (code, TRUE);
-
                        ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
 
                        ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
 
-                       /*
-                        * This nop will tell get_vcall_slot_addr that this is a virtual 
-                        * call.
-                        */
-                       ia64_nop_i (code, 0x12345);
-
                        ia64_br_call_reg (code, IA64_B0, IA64_B6);
 
-                       ia64_codegen_set_one_ins_per_bundle (code, FALSE);
-
                        code = emit_move_return_value (cfg, ins, code);
                        break;
                }
@@ -3014,6 +3007,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ia64_movl (code, GP_SCRATCH_REG2, 0);
                        ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
                        ia64_br_cond_reg (code, IA64_B6);
+                       // FIXME:
+                       //mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
                        ia64_codegen_set_one_ins_per_bundle (code, FALSE);
                        break;
                case OP_START_HANDLER: {
@@ -3781,7 +3776,7 @@ ia64_patch (unsigned char* code, gpointer target)
 }
 
 void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
+mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
 {
        MonoJumpInfo *patch_info;
 
@@ -3816,7 +3811,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
 
-       cfg->code_size =  MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
+       cfg->code_size =  MAX (cfg->header->code_size * 4, 512);
 
        if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
                cfg->code_size += 1024;
@@ -4057,7 +4052,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        while (cfg->code_len + max_epilog_size > cfg->code_size) {
                cfg->code_size *= 2;
                cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
-               mono_jit_stats.code_reallocs++;
+               cfg->stat_code_reallocs++;
        }
 
        /* FIXME: Emit unwind info */
@@ -4171,7 +4166,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
        while (cfg->code_len + code_size > (cfg->code_size - 16)) {
                cfg->code_size *= 2;
                cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
-               mono_jit_stats.code_reallocs++;
+               cfg->stat_code_reallocs++;
        }
 
        ia64_codegen_init (code, cfg->native_code + cfg->code_len);
@@ -4365,7 +4360,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean ena
 }
 
 void*
-mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
+mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
 {
        Ia64CodegenState code;
        CallInfo *cinfo = NULL;
@@ -4512,94 +4507,17 @@ mono_arch_get_patch_offset (guint8 *code)
        return 0;
 }
 
-gpointer
-mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
-{
-       guint8 *bundle2 = code - 48;
-       guint8 *bundle3 = code - 32;
-       guint8 *bundle4 = code - 16;
-       guint64 ins21 = ia64_bundle_ins1 (bundle2);
-       guint64 ins22 = ia64_bundle_ins2 (bundle2);
-       guint64 ins23 = ia64_bundle_ins3 (bundle2);
-       guint64 ins31 = ia64_bundle_ins1 (bundle3);
-       guint64 ins32 = ia64_bundle_ins2 (bundle3);
-       guint64 ins33 = ia64_bundle_ins3 (bundle3);
-       guint64 ins41 = ia64_bundle_ins1 (bundle4);
-       guint64 ins42 = ia64_bundle_ins2 (bundle4);
-       guint64 ins43 = ia64_bundle_ins3 (bundle4);
-
-       /* 
-        * Virtual calls are made with:
-        *
-        * [MII]       ld8 r31=[r8]
-        *             nop.i 0x0
-        *             nop.i 0x0;;
-        * [MII]       nop.m 0x0
-        *             mov.sptk b6=r31,0x2000000000f32a80
-        *             nop.i 0x0
-        * [MII]       nop.m 0x0
-        *             nop.i 0x123456
-        *             nop.i 0x0
-        * [MIB]       nop.m 0x0
-        *             nop.i 0x0
-        *             br.call.sptk.few b0=b6;;
-        */
-
-       if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
-                (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
-               (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
-               (ins31 == IA64_NOP_M) && 
-               (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
-               (ins33 == IA64_NOP_I) &&
-               (ins41 == IA64_NOP_M) &&
-               (ins42 == IA64_NOP_I) &&
-               (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
-               ((ins32 >> 6) & 0xfffff) == 0x12345) {
-               g_assert (ins21 == IA64_NOP_M);
-               g_assert (ins23 == IA64_NOP_I);
-               g_assert (ia64_ins_opcode (ins22) == 0);
-               g_assert (ia64_ins_x3 (ins22) == 7);
-               g_assert (ia64_ins_x (ins22) == 0);
-               g_assert (ia64_ins_b1 (ins22) == IA64_B6);
-
-               *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
-
-               return regs [IA64_R11];
-       }
-
-       return NULL;
-}
-
-gpointer*
-mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
-{
-       gpointer vt;
-       int displacement;
-       vt = mono_arch_get_vcall_slot (code, regs, &displacement);
-       if (!vt)
-               return NULL;
-       return (gpointer*)(gpointer)((char*)vt + displacement);
-}
-
 gpointer*
-mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
+mono_arch_get_delegate_method_ptr_addr (guint8* code, mgreg_t *regs)
 {
        NOT_IMPLEMENTED;
 
        return NULL;
 }
 
-static gboolean tls_offset_inited = FALSE;
-
 void
-mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
+mono_arch_finish_init (void)
 {
-       if (!tls_offset_inited) {
-               tls_offset_inited = TRUE;
-
-               appdomain_tls_offset = mono_domain_get_tls_offset ();
-               thread_tls_offset = mono_thread_get_tls_offset ();
-       }               
 }
 
 void
@@ -4621,8 +4539,6 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        guint8 *start, *buf;
        Ia64CodegenState code;
 
-       g_assert (!fail_tramp);
-
        size = count * 256;
        buf = g_malloc0 (size);
        ia64_codegen_init (code, buf);
@@ -4634,18 +4550,33 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                ia64_begin_bundle (code);
                item->code_target = (guint8*)code.buf + code.nins;
                if (item->is_equals) {
-                       if (item->check_target_idx) {
-                               if (!item->compare_done) {
+                       gboolean fail_case = !item->check_target_idx && fail_tramp;
+
+                       if (item->check_target_idx || fail_case) {
+                               if (!item->compare_done || fail_case) {
                                        ia64_movl (code, GP_SCRATCH_REG, item->key);
                                        ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
                                }
                                item->jmp_code = (guint8*)code.buf + code.nins;
                                ia64_br_cond_pred (code, 7, 0);
 
-                               ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
-                               ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
+                               if (item->has_target_code) {
+                                       ia64_movl (code, GP_SCRATCH_REG, item->value.target_code);
+                               } else {
+                                       ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
+                                       ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
+                               }
                                ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
                                ia64_br_cond_reg (code, IA64_B6);
+
+                               if (fail_case) {
+                                       ia64_begin_bundle (code);
+                                       ia64_patch (item->jmp_code, (guint8*)code.buf + code.nins);
+                                       ia64_movl (code, GP_SCRATCH_REG, fail_tramp);
+                                       ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
+                                       ia64_br_cond_reg (code, IA64_B6);
+                                       item->jmp_code = NULL;
+                               }
                        } else {
                                /* enable the commented code to assert on wrong method */
 #if ENABLE_WRONG_METHOD_CHECK
@@ -4680,7 +4611,12 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        g_assert (code.buf - buf <= size);
 
        size = code.buf - buf;
-       start = mono_code_manager_reserve (domain->code_mp, size);
+       if (fail_tramp) {
+               start = mono_method_alloc_generic_virtual_thunk (domain, size + 16);
+               start = (gpointer)ALIGN_TO (start, 16);
+       } else {
+               start = mono_domain_code_reserve (domain, size);
+       }
        memcpy (start, buf, size);
 
        mono_arch_flush_icache (start, size);
@@ -4691,9 +4627,9 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
 }
 
 MonoMethod*
-mono_arch_find_imt_method (gpointer *regs, guint8 *code)
+mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
 {
-       return regs [IA64_R9];
+       return (MonoMethod*)regs [IA64_R9];
 }
 
 void
@@ -4704,17 +4640,11 @@ mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt
 #endif
 
 gpointer
-mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
+mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
 {
        return (gpointer)regs [IA64_R10];
 }
 
-MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
-{
-       return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
-}
-
 gpointer
 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
 {
@@ -4817,31 +4747,13 @@ mono_arch_print_tree (MonoInst *tree, int arity)
        return 0;
 }
 
-MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
-{
-       MonoInst* ins;
-       
-       if (appdomain_tls_offset == -1)
-               return NULL;
-       
-       MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->inst_offset = appdomain_tls_offset;
-       return ins;
-}
-
-MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
+MonoInst*
+mono_arch_get_domain_intrinsic (MonoCompile* cfg)
 {
-       MonoInst* ins;
-       
-       if (thread_tls_offset == -1)
-               return NULL;
-       
-       MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->inst_offset = thread_tls_offset;
-       return ins;
+       return mono_get_domain_intrinsic (cfg);
 }
 
-gpointer
+mgreg_t
 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
 {
        /* FIXME: implement */