Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mono / mini / mini-llvm.c
index ba19a35dc1b6d818cb65888686677d6ef877c633..8ae614a20b2d2574dfd3f013c7ade8e7556b030f 100644 (file)
@@ -35,6 +35,9 @@ typedef struct {
        LLVMValueRef got_var;
        const char *got_symbol;
        GHashTable *plt_entries;
+       char **bb_names;
+       GPtrArray *used;
+       LLVMTypeRef ptr_type;
 } MonoLLVMModule;
 
 /*
@@ -88,6 +91,7 @@ typedef struct {
        gboolean *is_dead;
        gboolean *unreachable;
        int *pindexes;
+       LLVMValueRef imt_rgctx_loc;
 
        char temp_name [32];
 } EmitContext;
@@ -145,6 +149,12 @@ llvm_ins_info[] = {
 #define IS_TARGET_X86 0
 #endif
 
+#ifdef TARGET_AMD64
+#define IS_TARGET_AMD64 1
+#else
+#define IS_TARGET_AMD64 0
+#endif
+
 #define LLVM_FAILURE(ctx, reason) do { \
        TRACE_FAILURE (reason); \
        (ctx)->cfg->exception_message = g_strdup (reason); \
@@ -205,6 +215,18 @@ IntPtrType (void)
        return sizeof (gpointer) == 8 ? LLVMInt64Type () : LLVMInt32Type ();
 }
 
+static LLVMTypeRef
+ObjRefType (void)
+{
+       return sizeof (gpointer) == 8 ? LLVMPointerType (LLVMInt64Type (), 0) : LLVMPointerType (LLVMInt32Type (), 0);
+}
+
+static LLVMTypeRef
+ThisType (void)
+{
+       return sizeof (gpointer) == 8 ? LLVMPointerType (LLVMInt64Type (), 0) : LLVMPointerType (LLVMInt32Type (), 0);
+}
+
 /*
  * get_vtype_size:
  *
@@ -217,7 +239,7 @@ get_vtype_size (MonoType *t)
 
        size = mono_class_value_size (mono_class_from_mono_type (t), NULL);
 
-       while (size < sizeof (gpointer) && mono_is_power_of_two (size) == -1)
+       while (size < 2 * sizeof (gpointer) && mono_is_power_of_two (size) == -1)
                size ++;
 
        return size;
@@ -326,14 +348,14 @@ type_to_llvm_type (EmitContext *ctx, MonoType *t)
        case MONO_TYPE_SZARRAY:
        case MONO_TYPE_STRING:
        case MONO_TYPE_PTR:
-               return IntPtrType ();
+               return ObjRefType ();
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
                /* Because of generic sharing */
-               return IntPtrType ();
+               return ObjRefType ();
        case MONO_TYPE_GENERICINST:
                if (!mono_type_generic_inst_is_valuetype (t))
-                       return IntPtrType ();
+                       return ObjRefType ();
                /* Fall through */
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_TYPEDBYREF: {
@@ -833,14 +855,28 @@ simd_op_to_llvm_type (int opcode)
 static LLVMBasicBlockRef
 get_bb (EmitContext *ctx, MonoBasicBlock *bb)
 {
-       char bb_name [128];
+       char bb_name_buf [128];
+       char *bb_name;
 
        if (ctx->bblocks [bb->block_num].bblock == NULL) {
                if (bb->flags & BB_EXCEPTION_HANDLER) {
                        int clause_index = (mono_get_block_region_notry (ctx->cfg, bb->region) >> 8) - 1;
-                       sprintf (bb_name, "EH_CLAUSE%d_BB%d", clause_index, bb->block_num);
+                       sprintf (bb_name_buf, "EH_CLAUSE%d_BB%d", clause_index, bb->block_num);
+                       bb_name = bb_name_buf;
+               } else if (bb->block_num < 256) {
+                       if (!ctx->lmodule->bb_names)
+                               ctx->lmodule->bb_names = g_new0 (char*, 256);
+                       if (!ctx->lmodule->bb_names [bb->block_num]) {
+                               char *n;
+
+                               n = g_strdup_printf ("BB%d", bb->block_num);
+                               mono_memory_barrier ();
+                               ctx->lmodule->bb_names [bb->block_num] = n;
+                       }
+                       bb_name = ctx->lmodule->bb_names [bb->block_num];
                } else {
-                       sprintf (bb_name, "BB%d", bb->block_num);
+                       sprintf (bb_name_buf, "BB%d", bb->block_num);
+                       bb_name = bb_name_buf;
                }
 
                ctx->bblocks [bb->block_num].bblock = LLVMAppendBasicBlock (ctx->lmethod, bb_name);
@@ -934,12 +970,12 @@ convert_full (EmitContext *ctx, LLVMValueRef v, LLVMTypeRef dtype, gboolean is_u
                if (LLVMGetTypeKind (stype) == LLVMPointerTypeKind)
                        return LLVMBuildPtrToInt (ctx->builder, v, dtype, "");
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-               if (stype == LLVMInt32Type () && dtype == LLVMFloatType ())
-                       return LLVMBuildBitCast (ctx->builder, v, dtype, "");
-               if (stype == LLVMInt32Type () && dtype == LLVMDoubleType ())
-                       return LLVMBuildBitCast (ctx->builder, LLVMBuildZExt (ctx->builder, v, LLVMInt64Type (), ""), dtype, "");
-#endif
+               if (mono_arch_is_soft_float ()) {
+                       if (stype == LLVMInt32Type () && dtype == LLVMFloatType ())
+                               return LLVMBuildBitCast (ctx->builder, v, dtype, "");
+                       if (stype == LLVMInt32Type () && dtype == LLVMDoubleType ())
+                               return LLVMBuildBitCast (ctx->builder, LLVMBuildZExt (ctx->builder, v, LLVMInt64Type (), ""), dtype, "");
+               }
 
                if (LLVMGetTypeKind (stype) == LLVMVectorTypeKind && LLVMGetTypeKind (dtype) == LLVMVectorTypeKind)
                        return LLVMBuildBitCast (ctx->builder, v, dtype, "");
@@ -1044,7 +1080,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                } else {
                        g_assert_not_reached ();
                }
-       } else if (cinfo && MONO_TYPE_ISSTRUCT (sig->ret)) {
+       } else if (cinfo && mini_type_is_vtype (ctx->cfg, sig->ret)) {
                g_assert (cinfo->ret.storage == LLVMArgVtypeRetAddr);
                vretaddr = TRUE;
                ret_type = LLVMVoidType ();
@@ -1056,13 +1092,13 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
        if (cinfo && cinfo->rgctx_arg) {
                if (sinfo)
                        sinfo->rgctx_arg_pindex = pindex;
-               param_types [pindex] = IntPtrType ();
+               param_types [pindex] = ctx->lmodule->ptr_type;
                pindex ++;
        }
        if (cinfo && cinfo->imt_arg) {
                if (sinfo)
                        sinfo->imt_arg_pindex = pindex;
-               param_types [pindex] = IntPtrType ();
+               param_types [pindex] = ctx->lmodule->ptr_type;
                pindex ++;
        }
        if (vretaddr) {
@@ -1092,7 +1128,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
        if (sig->hasthis) {
                if (sinfo)
                        sinfo->this_arg_pindex = pindex;
-               param_types [pindex ++] = IntPtrType ();
+               param_types [pindex ++] = ThisType ();
        }
        if (vretaddr && vret_arg_pindex == pindex)
                param_types [pindex ++] = IntPtrType ();
@@ -1274,12 +1310,26 @@ set_metadata_flag (LLVMValueRef v, const char *flag_name)
 {
        LLVMValueRef md_arg;
        int md_kind;
-       
+
        md_kind = LLVMGetMDKindID (flag_name, strlen (flag_name));
        md_arg = LLVMMDString ("mono", 4);
        LLVMSetMetadata (v, md_kind, LLVMMDNode (&md_arg, 1));
 }
 
+static void
+set_invariant_load_flag (LLVMValueRef v)
+{
+       LLVMValueRef md_arg;
+       int md_kind;
+       const char *flag_name;
+
+       // FIXME: Cache this
+       flag_name = "invariant.load";
+       md_kind = LLVMGetMDKindID (flag_name, strlen (flag_name));
+       md_arg = LLVMMDString ("<index>", strlen ("<index>"));
+       LLVMSetMetadata (v, md_kind, LLVMMDNode (&md_arg, 1));
+}
+
 /*
  * emit_call:
  *
@@ -1475,7 +1525,8 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
                throw_sig->ret = &mono_get_void_class ()->byval_arg;
                throw_sig->params [0] = &mono_get_int32_class ()->byval_arg;
                icall_name = "llvm_throw_corlib_exception_abs_trampoline";
-               throw_sig->params [1] = &mono_get_intptr_class ()->byval_arg;
+               /* This will become i8* */
+               throw_sig->params [1] = &mono_get_byte_class ()->this_arg;
                sig = sig_to_llvm_sig (ctx, throw_sig);
 
                if (ctx->cfg->compile_aot) {
@@ -1486,8 +1537,7 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
                        /*
                         * Differences between the LLVM/non-LLVM throw corlib exception trampoline:
                         * - On x86, LLVM generated code doesn't push the arguments
-                        * - When using the LLVM mono branch, the trampoline takes the throw address as an
-                        *   arguments, not a pc offset.
+                        * - The trampoline takes the throw address as an arguments, not a pc offset.
                         */
                        LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, icall_name));
                }
@@ -1496,7 +1546,7 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
                ctx->lmodule->throw_corlib_exception = callee;
        }
 
-       if (IS_TARGET_X86)
+       if (IS_TARGET_X86 || IS_TARGET_AMD64)
                args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token - MONO_TOKEN_TYPE_DEF, FALSE);
        else
                args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token, FALSE);
@@ -1505,7 +1555,7 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
         * The LLVM mono branch contains changes so a block address can be passed as an
         * argument to a call.
         */
-       args [1] = LLVMBuildPtrToInt (builder, LLVMBlockAddress (ctx->lmethod, ex_bb), IntPtrType (), "");
+       args [1] = LLVMBlockAddress (ctx->lmethod, ex_bb);
        emit_call (ctx, bb, &builder, ctx->lmodule->throw_corlib_exception, args, 2);
 
        LLVMBuildUnreachable (builder);
@@ -1614,6 +1664,19 @@ emit_vtype_to_reg (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMVa
        *nregs = pindex;
 }
 
+static LLVMValueRef
+build_alloca_llvm_type (EmitContext *ctx, LLVMTypeRef t, int align)
+{
+       /*
+        * Have to place all alloca's at the end of the entry bb, since otherwise they would
+        * get executed every time control reaches them.
+        */
+       LLVMPositionBuilder (ctx->alloca_builder, get_bb (ctx, ctx->cfg->bb_entry), ctx->last_alloca);
+
+       ctx->last_alloca = mono_llvm_build_alloca (ctx->alloca_builder, t, NULL, align, "");
+       return ctx->last_alloca;
+}
+
 static LLVMValueRef
 build_alloca (EmitContext *ctx, MonoType *t)
 {
@@ -1629,29 +1692,37 @@ build_alloca (EmitContext *ctx, MonoType *t)
        while (mono_is_power_of_two (align) == -1)
                align ++;
 
-       /*
-        * Have to place all alloca's at the end of the entry bb, since otherwise they would
-        * get executed every time control reaches them.
-        */
-       LLVMPositionBuilder (ctx->alloca_builder, get_bb (ctx, ctx->cfg->bb_entry), ctx->last_alloca);
-
-       ctx->last_alloca = mono_llvm_build_alloca (ctx->alloca_builder, type_to_llvm_type (ctx, t), NULL, align, "");
-       return ctx->last_alloca;
+       return build_alloca_llvm_type (ctx, type_to_llvm_type (ctx, t), align);
 }
 
 /*
  * Put the global into the 'llvm.used' array to prevent it from being optimized away.
  */
 static void
-mark_as_used (LLVMModuleRef module, LLVMValueRef global)
+mark_as_used (MonoLLVMModule *lmodule, LLVMValueRef global)
 {
+       if (!lmodule->used)
+               lmodule->used = g_ptr_array_sized_new (16);
+       g_ptr_array_add (lmodule->used, global);
+}
+
+static void
+emit_llvm_used (MonoLLVMModule *lmodule)
+{
+       LLVMModuleRef module = lmodule->module;
        LLVMTypeRef used_type;
-       LLVMValueRef used, used_elem;
+       LLVMValueRef used, *used_elem;
+       int i;
                
-       used_type = LLVMArrayType (LLVMPointerType (LLVMInt8Type (), 0), 1);
+       if (!lmodule->used)
+               return;
+
+       used_type = LLVMArrayType (LLVMPointerType (LLVMInt8Type (), 0), lmodule->used->len);
        used = LLVMAddGlobal (module, used_type, "llvm.used");
-       used_elem = LLVMConstBitCast (global, LLVMPointerType (LLVMInt8Type (), 0));
-       LLVMSetInitializer (used, LLVMConstArray (LLVMPointerType (LLVMInt8Type (), 0), &used_elem, 1));
+       used_elem = g_new0 (LLVMValueRef, lmodule->used->len);
+       for (i = 0; i < lmodule->used->len; ++i)
+               used_elem [i] = LLVMConstBitCast (g_ptr_array_index (lmodule->used, i), LLVMPointerType (LLVMInt8Type (), 0));
+       LLVMSetInitializer (used, LLVMConstArray (LLVMPointerType (LLVMInt8Type (), 0), used_elem, lmodule->used->len));
        LLVMSetLinkage (used, LLVMAppendingLinkage);
        LLVMSetSection (used, "llvm.metadata");
 }
@@ -1680,7 +1751,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                MonoInst *var = cfg->varinfo [i];
                LLVMTypeRef vtype;
 
-               if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || MONO_TYPE_ISSTRUCT (var->inst_vtype)) {
+               if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || mini_type_is_vtype (cfg, var->inst_vtype)) {
                        vtype = type_to_llvm_type (ctx, var->inst_vtype);
                        CHECK_FAILURE (ctx);
                        /* Could be already created by an OP_VPHI */
@@ -1733,7 +1804,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
        if (sig->hasthis)
                emit_volatile_store (ctx, cfg->args [0]->dreg);
        for (i = 0; i < sig->param_count; ++i)
-               if (!MONO_TYPE_ISSTRUCT (sig->params [i]))
+               if (!mini_type_is_vtype (cfg, sig->params [i]))
                        emit_volatile_store (ctx, cfg->args [i + sig->hasthis]->dreg);
 
        if (sig->hasthis && !cfg->rgctx_var && cfg->generic_sharing_context) {
@@ -1745,7 +1816,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                 * with the "mono.this" custom metadata to tell llvm that it needs to save its
                 * location into the LSDA.
                 */
-               this_alloc = mono_llvm_build_alloca (builder, IntPtrType (), LLVMConstInt (LLVMInt32Type (), 1, FALSE), 0, "");
+               this_alloc = mono_llvm_build_alloca (builder, ThisType (), LLVMConstInt (LLVMInt32Type (), 1, FALSE), 0, "");
                /* This volatile store will keep the alloca alive */
                mono_llvm_build_store (builder, ctx->values [cfg->args [0]->dreg], this_alloc, TRUE);
 
@@ -1761,7 +1832,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                g_assert (ctx->addresses [cfg->rgctx_var->dreg]);
                rgctx_alloc = ctx->addresses [cfg->rgctx_var->dreg];
                /* This volatile store will keep the alloca alive */
-               store = mono_llvm_build_store (builder, ctx->rgctx_arg, rgctx_alloc, TRUE);
+               store = mono_llvm_build_store (builder, convert (ctx, ctx->rgctx_arg, IntPtrType ()), rgctx_alloc, TRUE);
 
                set_metadata_flag (rgctx_alloc, "mono.this");
        }
@@ -1865,6 +1936,10 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                                LLVMAddGlobalMapping (ee, callee, target);
                        }
                }
+
+               if (call->method && strstr (call->method->klass->name, "AsyncVoidMethodBuilder"))
+                       /* LLVM miscompiles async methods */
+                       LLVM_FAILURE (ctx, "#13734");
        } else if (calli) {
        } else {
                MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
@@ -1952,12 +2027,31 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        if (call->rgctx_arg_reg) {
                g_assert (values [call->rgctx_arg_reg]);
                g_assert (sinfo.rgctx_arg_pindex < nargs);
-               args [sinfo.rgctx_arg_pindex] = values [call->rgctx_arg_reg];
+               /*
+                * On ARM, the imt/rgctx argument is passed in a caller save register, but some of our trampolines etc. clobber it, leading to
+                * problems is LLVM moves the arg assignment earlier. To work around this, save the argument into a stack slot and load
+                * it using a volatile load.
+                */
+#ifdef TARGET_ARM
+               if (!ctx->imt_rgctx_loc)
+                       ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->lmodule->ptr_type, sizeof (gpointer));
+               LLVMBuildStore (builder, convert (ctx, ctx->values [call->rgctx_arg_reg], ctx->lmodule->ptr_type), ctx->imt_rgctx_loc);
+               args [sinfo.rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
+#else
+               args [sinfo.rgctx_arg_pindex] = convert (ctx, values [call->rgctx_arg_reg], ctx->lmodule->ptr_type);
+#endif
        }
        if (call->imt_arg_reg) {
                g_assert (values [call->imt_arg_reg]);
                g_assert (sinfo.imt_arg_pindex < nargs);
-               args [sinfo.imt_arg_pindex] = values [call->imt_arg_reg];
+#ifdef TARGET_ARM
+               if (!ctx->imt_rgctx_loc)
+                       ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->lmodule->ptr_type, sizeof (gpointer));
+               LLVMBuildStore (builder, convert (ctx, ctx->values [call->imt_arg_reg], ctx->lmodule->ptr_type), ctx->imt_rgctx_loc);
+               args [sinfo.imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
+#else
+               args [sinfo.imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->lmodule->ptr_type);
+#endif
        }
 
        if (vretaddr) {
@@ -2005,7 +2099,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                } else {
                        g_assert (args [pindex]);
                        if (i == 0 && sig->hasthis)
-                               args [pindex] = convert (ctx, args [pindex], IntPtrType ());
+                               args [pindex] = convert (ctx, args [pindex], ThisType ());
                        else
                                args [pindex] = convert (ctx, args [pindex], type_to_llvm_arg_type (ctx, sig->params [i - sig->hasthis]));
                }
@@ -2021,7 +2115,6 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
 
        lcall = emit_call (ctx, bb, &builder, callee, args, LLVMCountParamTypes (llvm_sig));
 
-#ifdef LLVM_MONO_BRANCH
        /*
         * Modify cconv and parameter attributes to pass rgctx/imt correctly.
         */
@@ -2037,7 +2130,6 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                LLVMAddInstrAttribute (lcall, 1 + sinfo.rgctx_arg_pindex, LLVMInRegAttribute);
        if (call->imt_arg_reg)
                LLVMAddInstrAttribute (lcall, 1 + sinfo.imt_arg_pindex, LLVMInRegAttribute);
-#endif
 
        /* Add byval attributes if needed */
        for (i = 0; i < sig->param_count; ++i) {
@@ -2154,8 +2246,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        type_info = LLVMAddGlobal (module, LLVMInt32Type (), ti_name);
                        LLVMSetInitializer (type_info, LLVMConstInt (LLVMInt32Type (), clause_index, FALSE));
 
-                       LLVMSetLinkage (type_info, LLVMPrivateLinkage);
-                       LLVMSetVisibility (type_info, LLVMHiddenVisibility);
+                       /*
+                        * These symbols are not really used, the clause_index is embedded into the EH tables generated by DwarfMonoException in LLVM.
+                        */
+                       LLVMSetLinkage (type_info, LLVMInternalLinkage);
 
                        /* 
                         * Enabling this causes llc to crash:
@@ -2411,9 +2505,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        /* We use COMPARE+SETcc/Bcc, llvm uses SETcc+br cond */
                        if (ins->opcode == OP_FCOMPARE)
                                cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMDoubleType ()), convert (ctx, rhs, LLVMDoubleType ()), "");
-                       else if (ins->opcode == OP_COMPARE_IMM)
-                               cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], convert (ctx, lhs, IntPtrType ()), LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), "");
-                       else if (ins->opcode == OP_LCOMPARE_IMM) {
+                       else if (ins->opcode == OP_COMPARE_IMM) {
+                               if (LLVMGetTypeKind (LLVMTypeOf (lhs)) == LLVMPointerTypeKind && ins->inst_imm == 0)
+                                       cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], lhs, LLVMConstNull (LLVMTypeOf (lhs)), "");
+                               else
+                                       cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], convert (ctx, lhs, IntPtrType ()), LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), "");
+                       } else if (ins->opcode == OP_LCOMPARE_IMM) {
                                if (SIZEOF_REGISTER == 4 && COMPILE_LLVM (cfg))  {
                                        /* The immediate is encoded in two fields */
                                        guint64 l = ((guint64)(guint32)ins->inst_offset << 32) | ((guint32)ins->inst_imm);
@@ -2422,9 +2519,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                        cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], convert (ctx, lhs, LLVMInt64Type ()), LLVMConstInt (LLVMInt64Type (), ins->inst_imm, FALSE), "");
                                }
                        }
-                       else if (ins->opcode == OP_COMPARE)
-                               cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], convert (ctx, lhs, IntPtrType ()), convert (ctx, rhs, IntPtrType ()), "");
-                       else
+                       else if (ins->opcode == OP_COMPARE) {
+                               if (LLVMGetTypeKind (LLVMTypeOf (lhs)) == LLVMPointerTypeKind && LLVMTypeOf (lhs) == LLVMTypeOf (rhs))
+                                       cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], lhs, rhs, "");
+                               else
+                                       cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], convert (ctx, lhs, IntPtrType ()), convert (ctx, rhs, IntPtrType ()), "");
+                       } else
                                cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], lhs, rhs, "");
 
                        if (MONO_IS_COND_BRANCH_OP (ins->next)) {
@@ -2679,7 +2779,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_AND_IMM:
                case OP_MUL_IMM:
                case OP_SHL_IMM:
-               case OP_SHR_IMM: {
+               case OP_SHR_IMM:
+               case OP_SHR_UN_IMM: {
                        LLVMValueRef imm;
 
                        if (spec [MONO_INST_SRC1] == 'l') {
@@ -2755,6 +2856,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                values [ins->dreg] = LLVMBuildLShr (builder, lhs, imm, dname);
                                break;
                        case OP_LSHR_UN_IMM:
+                       case OP_SHR_UN_IMM:
                                values [ins->dreg] = LLVMBuildLShr (builder, lhs, imm, dname);
                                break;
                        default:
@@ -2866,10 +2968,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
                        break;
                case OP_SEXT_I4:
-                       values [ins->dreg] = LLVMBuildSExt (builder, lhs, LLVMInt64Type (), dname);
+                       values [ins->dreg] = LLVMBuildSExt (builder, convert (ctx, lhs, LLVMInt32Type ()), LLVMInt64Type (), dname);
                        break;
                case OP_ZEXT_I4:
-                       values [ins->dreg] = LLVMBuildZExt (builder, lhs, LLVMInt64Type (), dname);
+                       values [ins->dreg] = LLVMBuildZExt (builder, convert (ctx, lhs, LLVMInt32Type ()), LLVMInt64Type (), dname);
                        break;
                case OP_TRUNC_I4:
                        values [ins->dreg] = LLVMBuildTrunc (builder, lhs, LLVMInt32Type (), dname);
@@ -2966,12 +3068,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, dname, is_volatile);
 
-                       if (!is_volatile && (ins->flags & MONO_INST_CONSTANT_LOAD)) {
+                       if (!is_volatile && (ins->flags & MONO_INST_INVARIANT_LOAD)) {
                                /*
                                 * These will signal LLVM that these loads do not alias any stores, and
                                 * they can't fail, allowing them to be hoisted out of loops.
                                 */
-                               set_metadata_flag (values [ins->dreg], "mono.noalias");
+                               set_invariant_load_flag (values [ins->dreg]);
                                set_metadata_flag (values [ins->dreg], "mono.nofail.load");
                        }
 
@@ -3089,23 +3191,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        indexes [1] = LLVMConstInt (LLVMInt32Type (), (gssize)got_offset, FALSE);
                        got_entry_addr = LLVMBuildGEP (builder, ctx->lmodule->got_var, indexes, 2, "");
 
-                       // FIXME: This doesn't work right now, because it must be
-                       // paired with an invariant.end, and even then, its only in effect
-                       // inside its basic block
-#if 0
-                       {
-                               LLVMValueRef args [3];
-                               LLVMValueRef ptr, val;
-
-                               ptr = LLVMBuildBitCast (builder, got_entry_addr, LLVMPointerType (LLVMInt8Type (), 0), "ptr");
-
-                               args [0] = LLVMConstInt (LLVMInt64Type (), sizeof (gpointer), FALSE);
-                               args [1] = ptr;
-                               val = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.invariant.start"), args, 2, "");
-                       }
-#endif
-
                        values [ins->dreg] = LLVMBuildLoad (builder, got_entry_addr, dname);
+                       set_invariant_load_flag (values [ins->dreg]);
                        break;
                }
                case OP_NOT_REACHED:
@@ -3204,44 +3291,38 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildSelect (builder, v, lhs, rhs, dname);
                        break;
                }
-               case OP_ATOMIC_EXCHANGE_I4: {
-                       LLVMValueRef args [2];
-
-                       g_assert (ins->inst_offset == 0);
-
-                       args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt32Type (), 0));
-                       args [1] = rhs;
-
-                       values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
-                       break;
-               }
+               case OP_ATOMIC_EXCHANGE_I4:
                case OP_ATOMIC_EXCHANGE_I8: {
                        LLVMValueRef args [2];
+                       LLVMTypeRef t;
+                               
+                       if (ins->opcode == OP_ATOMIC_EXCHANGE_I4)
+                               t = LLVMInt32Type ();
+                       else
+                               t = LLVMInt64Type ();
 
                        g_assert (ins->inst_offset == 0);
 
-                       args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt64Type (), 0));
-                       args [1] = convert (ctx, rhs, LLVMInt64Type ());
-                       values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
-                       break;
-               }
-               case OP_ATOMIC_ADD_NEW_I4: {
-                       LLVMValueRef args [2];
-
-                       g_assert (ins->inst_offset == 0);
+                       args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
+                       args [1] = convert (ctx, rhs, t);
 
-                       args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt32Type (), 0));
-                       args [1] = rhs;
-                       values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
+                       values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
                        break;
                }
+               case OP_ATOMIC_ADD_NEW_I4:
                case OP_ATOMIC_ADD_NEW_I8: {
                        LLVMValueRef args [2];
+                       LLVMTypeRef t;
+                               
+                       if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
+                               t = LLVMInt32Type ();
+                       else
+                               t = LLVMInt64Type ();
 
                        g_assert (ins->inst_offset == 0);
 
-                       args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt64Type (), 0));
-                       args [1] = convert (ctx, rhs, LLVMInt64Type ());
+                       args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
+                       args [1] = convert (ctx, rhs, t);
                        values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
                        break;
                }
@@ -3250,11 +3331,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        LLVMValueRef args [3];
                        LLVMTypeRef t;
                                
-                       if (ins->opcode == OP_ATOMIC_CAS_I4) {
+                       if (ins->opcode == OP_ATOMIC_CAS_I4)
                                t = LLVMInt32Type ();
-                       } else {
+                       else
                                t = LLVMInt64Type ();
-                       }
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
                        /* comparand */
@@ -3285,15 +3365,32 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        // 256 == GS segment register
                        LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
 #endif
-
                        // FIXME: XEN
                        values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, LLVMConstInt (IntPtrType (), ins->inst_offset, TRUE), ptrtype, ""), "");
+#elif defined(TARGET_AMD64) && defined(TARGET_OSX)
+                       /* See mono_amd64_emit_tls_get () */
+                       int offset = mono_amd64_get_tls_gs_offset () + (ins->inst_offset * 8);
+
+                       // 256 == GS segment register
+                       LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
+                       values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, LLVMConstInt (IntPtrType (), offset, TRUE), ptrtype, ""), "");
 #else
                        LLVM_FAILURE (ctx, "opcode tls-get");
 #endif
 
                        break;
                }
+               case OP_TLS_GET_REG: {
+#if defined(TARGET_AMD64) && defined(TARGET_OSX)
+                       /* See emit_tls_get_reg () */
+                       // 256 == GS segment register
+                       LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
+                       values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt32Type ()), ptrtype, ""), "");
+#else
+                       LLVM_FAILURE (ctx, "opcode tls-get");
+#endif
+                       break;
+               }
 
                        /*
                         * Overflow opcodes.
@@ -3370,11 +3467,18 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                break;
                        }
 
+                       if (mini_is_gsharedvt_klass (cfg, klass)) {
+                               // FIXME:
+                               LLVM_FAILURE (ctx, "gsharedvt");
+                               break;
+                       }
+
                        switch (ins->opcode) {
                        case OP_STOREV_MEMBASE:
-                               if (cfg->gen_write_barriers && klass->has_references && ins->inst_destbasereg != cfg->frame_reg) {
-                                       /* FIXME: Emit write barriers like in mini_emit_stobj () */
-                                       LLVM_FAILURE (ctx, "storev_membase + write barriers");
+                               if (cfg->gen_write_barriers && klass->has_references && ins->inst_destbasereg != cfg->frame_reg &&
+                                       LLVMGetInstructionOpcode (values [ins->inst_destbasereg]) != LLVMAlloca) {
+                                       /* Decomposed earlier */
+                                       g_assert_not_reached ();
                                        break;
                                }
                                if (!addresses [ins->sreg1]) {
@@ -3987,7 +4091,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                else
                                        ctx->lmodule->throw = callee;
                        }
-                       arg = convert (ctx, values [ins->sreg1], type_to_llvm_type (ctx, &mono_get_object_class ()->byval_arg));
+                       arg = convert (ctx, lhs, type_to_llvm_type (ctx, &mono_get_object_class ()->byval_arg));
                        emit_call (ctx, bb, &builder, callee, &arg, 1);
                        break;
                }
@@ -4128,7 +4232,7 @@ mono_llvm_check_method_supported (MonoCompile *cfg)
 #if 1
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
-               
+
                if (i > 0 && clause->try_offset <= header->clauses [i - 1].handler_offset + header->clauses [i - 1].handler_len) {
                        /*
                         * FIXME: Some tests still fail with nested clauses.
@@ -4195,7 +4299,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
        ctx->addresses = g_new0 (LLVMValueRef, cfg->next_vreg);
        ctx->vreg_types = g_new0 (LLVMTypeRef, cfg->next_vreg);
        ctx->vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg);
-       phi_values = g_ptr_array_new ();
+       phi_values = g_ptr_array_sized_new (256);
        /* 
         * This signals whenever the vreg was defined by a phi node with no input vars
         * (i.e. all its input bblocks end with NOT_REACHABLE).
@@ -4204,7 +4308,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
        /* Whenever the bblock is unreachable */
        ctx->unreachable = g_new0 (gboolean, cfg->max_block_num);
 
-       bblock_list = g_ptr_array_new ();
+       bblock_list = g_ptr_array_sized_new (256);
 
        ctx->values = values;
        ctx->region_to_handler = g_hash_table_new (NULL, NULL);
@@ -4221,18 +4325,21 @@ mono_llvm_emit_method (MonoCompile *cfg)
        
        module = ctx->module = ctx->lmodule->module;
 
+       if (cfg->gsharedvt)
+               LLVM_FAILURE (ctx, "gsharedvt");
+
 #if 1
        {
                static int count = 0;
                count ++;
 
-               if (getenv ("LLVM_COUNT")) {
-                       if (count == atoi (getenv ("LLVM_COUNT"))) {
+               if (g_getenv ("LLVM_COUNT")) {
+                       if (count == atoi (g_getenv ("LLVM_COUNT"))) {
                                printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
                                fflush (stdout);
                                last = TRUE;
                        }
-                       if (count > atoi (getenv ("LLVM_COUNT")))
+                       if (count > atoi (g_getenv ("LLVM_COUNT")))
                                LLVM_FAILURE (ctx, "");
                }
        }
@@ -4259,9 +4366,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
        method = LLVMAddFunction (module, method_name, method_type);
        ctx->lmethod = method;
 
-#ifdef LLVM_MONO_BRANCH
        LLVMSetFunctionCallConv (method, LLVMMono1CallConv);
-#endif
        LLVMSetLinkage (method, LLVMPrivateLinkage);
 
        LLVMAddFunctionAttr (method, LLVMUWTable);
@@ -4472,6 +4577,9 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                g_assert (LLVMTypeOf (ctx->addresses [sreg1]) == LLVMTypeOf (values [phi->dreg]));
                                LLVMAddIncoming (values [phi->dreg], &ctx->addresses [sreg1], &in_bb, 1);
                        } else {
+                               if (LLVMTypeOf (values [sreg1]) != LLVMTypeOf (values [phi->dreg]))
+                                       // FIXME:
+                                       LLVM_FAILURE (ctx, "incoming phi arg type mismatch");
                                g_assert (LLVMTypeOf (values [sreg1]) == LLVMTypeOf (values [phi->dreg]));
                                LLVMAddIncoming (values [phi->dreg], &values [sreg1], &in_bb, 1);
                        }
@@ -4494,7 +4602,21 @@ mono_llvm_emit_method (MonoCompile *cfg)
        if (cfg->verbose_level > 1)
                mono_llvm_dump_value (method);
 
-       mark_as_used (module, method);
+       if (cfg->compile_aot)
+               mark_as_used (ctx->lmodule, method);
+
+       if (cfg->compile_aot) {
+               LLVMValueRef md_args [16];
+               LLVMValueRef md_node;
+               int method_index;
+
+               method_index = mono_aot_get_method_index (cfg->orig_method);
+               md_args [0] = LLVMMDString (method_name, strlen (method_name));
+               md_args [1] = LLVMConstInt (LLVMInt32Type (), method_index, FALSE);
+               md_node = LLVMMDNode (md_args, 2);
+               LLVMAddNamedMetadataOperand (module, "mono.function_indexes", md_node);
+               //LLVMSetMetadata (method, md_kind, LLVMMDNode (&md_arg, 1));
+       }
 
        if (cfg->compile_aot) {
                /* Don't generate native code, keep the LLVM IR */
@@ -4679,6 +4801,8 @@ exception_cb (void *data)
         * with it.
         */
        cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info, &this_reg, &this_offset);
+       if (cfg->verbose_level > 1)
+               mono_print_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len);
 
        /* Count nested clauses */
        nested_len = 0;
@@ -4841,16 +4965,6 @@ add_intrinsics (LLVMModuleRef module)
                LLVMAddFunction (module, "llvm.umul.with.overflow.i64", LLVMFunctionType (LLVMStructType (ovf_res_i64, 2, FALSE), ovf_params_i64, 2, FALSE));
        }
 
-       {
-               LLVMTypeRef struct_ptr = LLVMPointerType (LLVMStructType (NULL, 0, FALSE), 0);
-               LLVMTypeRef invariant_start_params [] = { LLVMInt64Type (), LLVMPointerType (LLVMInt8Type (), 0) };
-               LLVMTypeRef invariant_end_params [] = { struct_ptr, LLVMInt64Type (), LLVMPointerType (LLVMInt8Type (), 0) };
-
-               LLVMAddFunction (module, "llvm.invariant.start", LLVMFunctionType (struct_ptr, invariant_start_params, 2, FALSE));
-
-               LLVMAddFunction (module, "llvm.invariant.end", LLVMFunctionType (LLVMVoidType (), invariant_end_params, 3, FALSE));
-       }
-
        /* EH intrinsics */
        {
                LLVMTypeRef arg_types [2];
@@ -4866,6 +4980,7 @@ add_intrinsics (LLVMModuleRef module)
        }
 
        /* SSE intrinsics */
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        {
                LLVMTypeRef ret_type, arg_types [16];
 
@@ -5010,6 +5125,7 @@ add_intrinsics (LLVMModuleRef module)
        }
 
        AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
+#endif
 
        /* Load/Store intrinsics */
        {
@@ -5034,6 +5150,12 @@ add_intrinsics (LLVMModuleRef module)
        }
 }
 
+static void
+add_types (MonoLLVMModule *lmodule)
+{
+       lmodule->ptr_type = LLVMPointerType (sizeof (gpointer) == 8 ? LLVMInt64Type () : LLVMInt32Type (), 0);
+}
+
 void
 mono_llvm_init (void)
 {
@@ -5060,6 +5182,7 @@ init_jit_module (void)
        ee = mono_llvm_create_ee (LLVMCreateModuleProviderForExistingModule (jit_module.module), alloc_cb, emitted_cb, exception_cb, dlsym_cb);
 
        add_intrinsics (jit_module.module);
+       add_types (&jit_module);
 
        jit_module.llvm_types = g_hash_table_new (NULL, NULL);
 
@@ -5102,6 +5225,7 @@ mono_llvm_create_aot_module (const char *got_symbol)
        aot_module.got_symbol = got_symbol;
 
        add_intrinsics (aot_module.module);
+       add_types (&aot_module);
 
        /* Add GOT */
        /*
@@ -5111,7 +5235,7 @@ mono_llvm_create_aot_module (const char *got_symbol)
         * its size is known in mono_llvm_emit_aot_module ().
         */
        {
-               LLVMTypeRef got_type = LLVMArrayType (IntPtrType (), 0);
+               LLVMTypeRef got_type = LLVMArrayType (aot_module.ptr_type, 0);
 
                aot_module.got_var = LLVMAddGlobal (aot_module.module, got_type, "mono_dummy_got");
                LLVMSetInitializer (aot_module.got_var, LLVMConstNull (got_type));
@@ -5124,7 +5248,7 @@ mono_llvm_create_aot_module (const char *got_symbol)
                LLVMValueRef personality;
 
                personality = LLVMAddFunction (aot_module.module, "mono_aot_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
-               LLVMSetLinkage (personality, LLVMPrivateLinkage);
+               LLVMSetLinkage (personality, LLVMInternalLinkage);
                lbb = LLVMAppendBasicBlock (personality, "BB0");
                lbuilder = LLVMCreateBuilder ();
                LLVMPositionBuilderAtEnd (lbuilder, lbb);
@@ -5148,18 +5272,20 @@ mono_llvm_emit_aot_module (const char *filename, int got_size)
         * Create the real got variable and replace all uses of the dummy variable with
         * the real one.
         */
-       got_type = LLVMArrayType (IntPtrType (), got_size);
+       got_type = LLVMArrayType (aot_module.ptr_type, got_size);
        real_got = LLVMAddGlobal (aot_module.module, got_type, aot_module.got_symbol);
        LLVMSetInitializer (real_got, LLVMConstNull (got_type));
        LLVMSetLinkage (real_got, LLVMInternalLinkage);
 
        mono_llvm_replace_uses_of (aot_module.got_var, real_got);
 
-       mark_as_used (aot_module.module, real_got);
+       mark_as_used (&aot_module, real_got);
 
        /* Delete the dummy got so it doesn't become a global */
        LLVMDeleteGlobal (aot_module.got_var);
 
+       emit_llvm_used (&aot_module);
+
 #if 0
        {
                char *verifier_err;