2010-02-10 Miguel de Icaza <miguel@novell.com>
[mono.git] / mono / mini / mini-llvm.c
index 8d2b485f53e1001cc88e227658f15d681280b48b..ec83b7a13f95b699cd1f0268c3e9c3eb6ddfa845 100644 (file)
@@ -8,8 +8,12 @@
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/mempool-internals.h>
 
+#ifndef __STDC_LIMIT_MACROS
 #define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
 #define __STDC_CONSTANT_MACROS
+#endif
 
 #include "llvm-c/Core.h"
 #include "llvm-c/ExecutionEngine.h"
@@ -68,6 +72,8 @@ typedef struct {
        MonoMethodSignature *sig;
        GSList *builders;
        GHashTable *region_to_handler;
+       LLVMBuilderRef alloca_builder;
+       LLVMValueRef last_alloca;
 
        char temp_name [32];
 } EmitContext;
@@ -161,6 +167,9 @@ static LLVMExecutionEngineRef ee;
 static guint32 current_cfg_tls_id;
 
 static MonoLLVMModule jit_module, aot_module;
+static gboolean jit_module_inited;
+
+static void init_jit_module (void);
 
 /*
  * IntPtrType:
@@ -458,6 +467,7 @@ op_to_llvm_type (int opcode)
        case OP_IMUL_OVF_UN:
                return LLVMInt32Type ();
        case OP_LADD_OVF:
+       case OP_LADD_OVF_UN:
        case OP_LSUB_OVF:
        case OP_LSUB_OVF_UN:
        case OP_LMUL_OVF:
@@ -582,6 +592,7 @@ static const char*
 simd_op_to_intrins (int opcode)
 {
        switch (opcode) {
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        case OP_MINPD:
                return "llvm.x86.sse2.min.pd";
        case OP_MINPS:
@@ -602,6 +613,7 @@ simd_op_to_intrins (int opcode)
                return "llvm.x86.sse41.pmaxuw";
        case OP_PMAXB_UN:
                return "llvm.x86.sse41.pmaxub";
+#endif
        default:
                g_assert_not_reached ();
                return NULL;
@@ -936,6 +948,8 @@ get_plt_entry (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gc
        if (!callee) {
                callee = LLVMAddFunction (ctx->module, callee_name, llvm_sig);
 
+               LLVMSetVisibility (callee, LLVMHiddenVisibility);
+
                g_hash_table_insert (ctx->lmodule->plt_entries, (char*)callee_name, callee);
        }
 
@@ -961,7 +975,7 @@ emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LL
        LLVMBuilderRef builder = *builder_ref;
 
        // FIXME: Nested clauses
-       if (bb->region && MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
+       if (bb->region != -1 && MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
                MonoMethodHeader *header = mono_method_get_header (cfg->method);
                // FIXME: Add a macro for this
                int clause_index = (bb->region >> 8) - 1;
@@ -1041,15 +1055,27 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
                        callee = get_plt_entry (ctx, sig, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_corlib_exception");
                } else {
                        callee = LLVMAddFunction (ctx->module, "throw_corlib_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
+
+#ifdef TARGET_X86 
+                       /* 
+                        * LLVM generated code doesn't push the arguments, so we need another
+                        * throw trampoline.
+                        */
+                       LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_llvm_throw_corlib_exception"));
+#else
                        LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_corlib_exception"));
+#endif
                }
 
                mono_memory_barrier ();
                ctx->lmodule->throw_corlib_exception = callee;
        }
 
+#ifdef TARGET_X86
+       args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token - MONO_TOKEN_TYPE_DEF, FALSE);
+#else
        args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token, FALSE);
+#endif
        /*
         * FIXME: The offset is 0, this is not a problem for exception handling
         * in general, because we don't llvm compile methods with handlers, its only
@@ -1178,7 +1204,14 @@ build_alloca (EmitContext *ctx, MonoType *t)
        while (mono_is_power_of_two (align) == -1)
                align ++;
 
-       return mono_llvm_build_alloca (ctx->builder, type_to_llvm_type (ctx, t), NULL, 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;
 }
 
 /*
@@ -1212,6 +1245,8 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
        LLVMCallInfo *linfo = ctx->linfo;
        MonoBasicBlock *bb;
 
+       ctx->alloca_builder = create_builder (ctx);
+
        /*
         * Handle indirect/volatile variables by allocating memory for them
         * using 'alloca', and storing their address in a temporary.
@@ -1251,6 +1286,11 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
                        ctx->addresses [reg] = build_alloca (ctx, sig->params [i]);
 
                        emit_reg_to_vtype (ctx, builder, sig->params [i], ctx->addresses [reg], ainfo, regs);
+
+                       if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (sig->params [i]))) {
+                               /* Treat these as normal values */
+                               ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
+                       }
                } else if (ainfo->storage == LLVMArgVtypeByVal) {
                        ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, pindexes [i]);
                } else {
@@ -1369,6 +1409,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                method_name = mono_aot_get_method_name (cfg);
                debug_name = mono_aot_get_method_debug_name (cfg);
        } else {
+               init_jit_module ();
                ctx->lmodule = &jit_module;
                method_name = mono_method_full_name (cfg->method, TRUE);
                debug_name = NULL;
@@ -1572,6 +1613,11 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        LLVMValueRef eh_selector, eh_exception, personality, args [4];
                        MonoInst *exvar;
                        static gint32 mapping_inited;
+                       static int ti_generator;
+                       char ti_name [128];
+                       MonoClass **ti;
+                       LLVMValueRef type_info;
+                       int clause_index;
 
                        if (!bblocks [bb->block_num].invoke_target) {
                                /*
@@ -1594,10 +1640,43 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        }
 
                        i8ptr = LLVMPointerType (LLVMInt8Type (), 0);
+
+                       clause_index = (mono_get_block_region_notry (cfg, bb->region) >> 8) - 1;
+
+                       /*
+                        * Create the type info
+                        */
+                       sprintf (ti_name, "type_info_%d", ti_generator);
+                       ti_generator ++;
+
+                       if (cfg->compile_aot) {
+                               /* decode_eh_frame () in aot-runtime.c will decode this */
+                               type_info = LLVMAddGlobal (module, LLVMInt32Type (), ti_name);
+                               LLVMSetInitializer (type_info, LLVMConstInt (LLVMInt32Type (), clause_index, FALSE));
+
+                               LLVMSetLinkage (type_info, LLVMPrivateLinkage);
+                               LLVMSetVisibility (type_info, LLVMHiddenVisibility);
+
+                               /* 
+                                * FIXME: llc currently generates incorrect data in the LSDA:
+                                *      .byte   0x9B                                        # @TType format (indirect pcrel sdata4)
+                                * and later:
+                                * .quad        type_info_1                                 # TypeInfo
+                                */
+                               LLVM_FAILURE (ctx, "aot+clauses");
+                       } else {
+                               /* exception_cb will decode this */
+                               ti = g_malloc (sizeof (MonoExceptionClause));
+                               memcpy (ti, &mono_method_get_header (cfg->method)->clauses [clause_index], sizeof (MonoExceptionClause));
+
+                               type_info = LLVMAddGlobal (module, i8ptr, ti_name);
+
+                               LLVMAddGlobalMapping (ee, type_info, ti);
+                       }
+
                        args [0] = LLVMConstNull (i8ptr);
                        args [1] = LLVMConstBitCast (personality, i8ptr);
-                       args [2] = LLVMConstNull (i8ptr);
-                       args [3] = LLVMConstNull (LLVMInt32Type ());
+                       args [2] = type_info;
                        LLVMBuildCall (builder, eh_selector, args, 3, "");
 
                        /* Store the exception into the exvar */
@@ -2348,9 +2427,10 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_LOADU4_MEM:
                        case OP_LOAD_MEM: {
                                int size = 8;
-                               LLVMValueRef index;
+                               LLVMValueRef index, addr;
                                LLVMTypeRef t;
                                gboolean sext = FALSE, zext = FALSE;
+                               gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
 
                                t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
@@ -2358,20 +2438,27 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        dname = (char*)"";
 
                                /* 
-                                * We emit volatile loads because otherwise LLVM will
-                                * generate invalid code when encountering a load from a
+                                * We emit volatile loads for loads which can fault, because otherwise
+                                * LLVM will generate invalid code when encountering a load from a
                                 * NULL address.
-                                * FIXME: Avoid this somehow.
                                 */
-                               g_assert (ins->inst_offset % size == 0);
                                if ((ins->opcode == OP_LOADI8_MEM) || (ins->opcode == OP_LOAD_MEM) || (ins->opcode == OP_LOADI4_MEM) || (ins->opcode == OP_LOADU4_MEM) || (ins->opcode == OP_LOADU1_MEM) || (ins->opcode == OP_LOADU2_MEM)) {
-                                       values [ins->dreg] = mono_llvm_build_volatile_load (builder, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), LLVMPointerType (t, 0)), dname);
+                                       addr = LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE);
                                } else if (ins->inst_offset == 0) {
-                                       values [ins->dreg] = mono_llvm_build_volatile_load (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), dname);
+                                       addr = values [ins->inst_basereg];
+                               } else if (ins->inst_offset % size != 0) {
+                                       /* Unaligned load */
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
                                } else {
                                        index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                                       values [ins->dreg] = mono_llvm_build_volatile_load (builder, LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), &index, 1, ""), dname);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), &index, 1, "");
                                }
+
+                               addr = convert (ctx, addr, LLVMPointerType (t, 0));
+
+                               values [ins->dreg] = mono_llvm_build_load (builder, addr, dname, is_volatile);
+
                                if (sext)
                                        values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
                                else if (zext)
@@ -2389,15 +2476,21 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_STORER8_MEMBASE_REG:
                        case OP_STORE_MEMBASE_REG: {
                                int size = 8;
-                               LLVMValueRef index;
+                               LLVMValueRef index, addr;
                                LLVMTypeRef t;
                                gboolean sext = FALSE, zext = FALSE;
 
                                t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
-                               g_assert (ins->inst_offset % size == 0);
-                               index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                               LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], t), LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""));
+                               if (ins->inst_offset % size != 0) {
+                                       /* Unaligned store */
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+                               } else {
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                               }
+                               LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)));
                                break;
                        }
 
@@ -2407,20 +2500,26 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_STOREI8_MEMBASE_IMM:
                        case OP_STORE_MEMBASE_IMM: {
                                int size = 8;
-                               LLVMValueRef index;
+                               LLVMValueRef index, addr;
                                LLVMTypeRef t;
                                gboolean sext = FALSE, zext = FALSE;
 
                                t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
-                               g_assert (ins->inst_offset % size == 0);
-                               index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                               LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""));
+                               if (ins->inst_offset % size != 0) {
+                                       /* Unaligned store */
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+                               } else {
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                               }
+                               LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), addr);
                                break;
                        }
 
                        case OP_CHECK_THIS:
-                               mono_llvm_build_volatile_load (builder, convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "");
+                               mono_llvm_build_load (builder, convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "", TRUE);
                                break;
                        case OP_OUTARG_VTRETADDR:
                                break;
@@ -2459,10 +2558,6 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                llvm_sig = sig_to_llvm_sig (ctx, sig, cinfo);
                                CHECK_FAILURE (ctx);
 
-                               if (call->rgctx_reg) {
-                                       LLVM_FAILURE (ctx, "rgctx reg");
-                               }
-
                                virtual = (ins->opcode == OP_VOIDCALL_MEMBASE || ins->opcode == OP_CALL_MEMBASE || ins->opcode == OP_VCALL_MEMBASE || ins->opcode == OP_LCALL_MEMBASE || ins->opcode == OP_FCALL_MEMBASE);
                                calli = (ins->opcode == OP_VOIDCALL_REG || ins->opcode == OP_CALL_REG || ins->opcode == OP_VCALL_REG || ins->opcode == OP_LCALL_REG || ins->opcode == OP_FCALL_REG);
 
@@ -2680,6 +2775,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                guint32 got_offset;
                                LLVMValueRef indexes [2];
                                MonoJumpInfo *ji;
+                               LLVMValueRef got_entry_addr;
 
                                /* 
                                 * FIXME: Can't allocate from the cfg mempool since that is freed if
@@ -2699,7 +2795,25 @@ mono_llvm_emit_method (MonoCompile *cfg)
  
                                indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
                                indexes [1] = LLVMConstInt (LLVMInt32Type (), (gssize)got_offset, FALSE);
-                               values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildGEP (builder, ctx->lmodule->got_var, indexes, 2, ""), dname);
+                               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);
                                break;
                        }
                        case OP_NOT_REACHED:
@@ -2744,6 +2858,14 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        }
                                */
 
+                       case OP_ABS: {
+                               LLVMValueRef args [1];
+
+                               args [0] = lhs;
+                               values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "fabs"), args, 1, dname);
+                               break;
+                       }
+
                        case OP_IMIN:
                        case OP_LMIN: {
                                LLVMValueRef v = LLVMBuildICmp (builder, LLVMIntSLE, lhs, rhs, "");
@@ -2877,6 +2999,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_IMUL_OVF_UN:
 #if SIZEOF_VOID_P == 8
                        case OP_LADD_OVF:
+                       case OP_LADD_OVF_UN:
                        case OP_LSUB_OVF:
                        case OP_LSUB_OVF_UN:
                        case OP_LMUL_OVF:
@@ -2995,6 +3118,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        /* 
                         * SIMD
                         */
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
                        case OP_XZERO: {
                                values [ins->dreg] = LLVMConstNull (type_to_llvm_type (ctx, &ins->klass->byval_arg));
                                break;
@@ -3149,6 +3273,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                values [ins->dreg] = LLVMBuildExtractElement (builder, lhs, LLVMConstInt (LLVMInt32Type (), ins->inst_c0, FALSE), "");
                                break;
                        }
+#endif
 
                        case OP_DUMMY_USE:
                                break;
@@ -3173,7 +3298,16 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                                callee = get_plt_entry (ctx, sig_to_llvm_sig (ctx, throw_sig, NULL), MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception");
                                        } else {
                                                callee = LLVMAddFunction (module, "mono_arch_throw_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
+
+#ifdef TARGET_X86
+                                               /* 
+                                                * LLVM doesn't push the exception argument, so we need a different
+                                                * trampoline.
+                                                */
+                                               LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_llvm_throw_exception"));
+#else
                                                LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception"));
+#endif
                                        }
 
                                        mono_memory_barrier ();
@@ -3287,6 +3421,9 @@ mono_llvm_emit_method (MonoCompile *cfg)
 
                if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID)
                        LLVMBuildRetVoid (builder);
+
+               if (bb == cfg->bb_entry)
+                       ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry));
        }
 
        /* Add incoming phi values */
@@ -3338,6 +3475,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                /* Can't delete the method if it has an alias, so only add it if successful */
                if (debug_name) {
                        debug_alias = LLVMAddAlias (module, LLVMTypeOf (method), method, debug_name);
+                       LLVMSetLinkage (debug_alias, LLVMInternalLinkage);
                        LLVMSetVisibility (debug_alias, LLVMHiddenVisibility);
                }
 
@@ -3503,7 +3641,8 @@ exception_cb (void *data)
 {
        MonoCompile *cfg;
        MonoJitExceptionInfo *ei;
-       guint32 ei_len;
+       guint32 ei_len, i;
+       gpointer *type_info;
 
        cfg = TlsGetValue (current_cfg_tls_id);
        g_assert (cfg);
@@ -3514,11 +3653,19 @@ exception_cb (void *data)
         * An alternative would be to save it directly, and modify our unwinder to work
         * with it.
         */
-       cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len);
+       cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info);
 
        cfg->llvm_ex_info = mono_mempool_alloc0 (cfg->mempool, ei_len * sizeof (MonoJitExceptionInfo));
        cfg->llvm_ex_info_len = ei_len;
        memcpy (cfg->llvm_ex_info, ei, ei_len * sizeof (MonoJitExceptionInfo));
+       /* Fill the rest of the information from the type info */
+       for (i = 0; i < ei_len; ++i) {
+               MonoExceptionClause *clause = type_info [i];
+
+               cfg->llvm_ex_info [i].flags = clause->flags;
+               cfg->llvm_ex_info [i].data.catch_class = clause->data.catch_class;
+       }
+
        g_free (ei);
 }
 
@@ -3544,6 +3691,9 @@ add_intrinsics (LLVMModuleRef module)
                LLVMAddFunction (module, "llvm.sin.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
                LLVMAddFunction (module, "llvm.cos.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
                LLVMAddFunction (module, "llvm.sqrt.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
+
+               /* This isn't an intrinsic, instead llvm seems to special case it by name */
+               LLVMAddFunction (module, "fabs", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
        }
 
        {
@@ -3582,6 +3732,16 @@ 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];
@@ -3637,6 +3797,20 @@ void
 mono_llvm_init (void)
 {
        current_cfg_tls_id = TlsAlloc ();
+}
+
+static void
+init_jit_module (void)
+{
+       if (jit_module_inited)
+               return;
+
+       mono_loader_lock ();
+
+       if (jit_module_inited) {
+               mono_loader_unlock ();
+               return;
+       }
 
        jit_module.module = LLVMModuleCreateWithName ("mono");
 
@@ -3647,14 +3821,20 @@ mono_llvm_init (void)
        jit_module.llvm_types = g_hash_table_new (NULL, NULL);
 
        LLVMAddGlobalMapping (ee, LLVMGetNamedFunction (jit_module.module, "mono_resume_unwind"), mono_resume_unwind);
+
+       jit_module_inited = TRUE;
+
+       mono_loader_unlock ();
 }
 
 void
 mono_llvm_cleanup (void)
 {
-       mono_llvm_dispose_ee (ee);
+       if (ee)
+               mono_llvm_dispose_ee (ee);
 
-       g_hash_table_destroy (jit_module.llvm_types);
+       if (jit_module.llvm_types)
+               g_hash_table_destroy (jit_module.llvm_types);
 }
 
 void
@@ -3685,15 +3865,6 @@ mono_llvm_create_aot_module (const char *got_symbol)
                LLVMSetInitializer (aot_module.got_var, LLVMConstNull (got_type));
        }
 
-       /* Add a method to generate the 'methods' symbol needed by the AOT compiler */
-       {
-               LLVMValueRef methods_method = LLVMAddFunction (aot_module.module, "methods", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
-               LLVMBasicBlockRef bb = LLVMAppendBasicBlock (methods_method, "BB_ENTRY");
-               LLVMBuilderRef builder = LLVMCreateBuilder ();
-               LLVMPositionBuilderAtEnd (builder, bb);
-               LLVMBuildRetVoid (builder);
-       }
-
        /* Add a dummy personality function */
        {
                LLVMBasicBlockRef lbb;
@@ -3734,6 +3905,9 @@ mono_llvm_emit_aot_module (const char *filename, int got_size)
 
        mark_as_used (aot_module.module, real_got);
 
+       /* Delete the dummy got so it doesn't become a global */
+       LLVMDeleteGlobal (aot_module.got_var);
+
 #if 0
        {
                char *verifier_err;