Merge pull request #498 from Unroll-Me/master
[mono.git] / mono / mini / mini-llvm.c
index ac5adf9f15af21ee9859fbb1963e0bf142065473..33b697da5ec089adaa0aef365c08f21f6466d76c 100644 (file)
@@ -1,13 +1,15 @@
 /*
  * mini-llvm.c: llvm "Backend" for the mono JIT
  *
- * (C) 2009 Novell, Inc.
+ * Copyright 2009-2011 Novell Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
  */
 
 #include "mini.h"
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/mempool-internals.h>
 #include <mono/utils/mono-tls.h>
+#include <mono/utils/mono-dl.h>
 
 #ifndef __STDC_LIMIT_MACROS
 #define __STDC_LIMIT_MACROS
@@ -189,7 +191,6 @@ static gboolean jit_module_inited;
 static int memset_param_count, memcpy_param_count;
 static const char *memset_func_name;
 static const char *memcpy_func_name;
-static const char *eh_selector_name;
 
 static void init_jit_module (void);
 
@@ -325,7 +326,7 @@ type_to_llvm_type (EmitContext *ctx, MonoType *t)
        case MONO_TYPE_SZARRAY:
        case MONO_TYPE_STRING:
        case MONO_TYPE_PTR:
-               return LLVMPointerType (IntPtrType (), 0);
+               return IntPtrType ();
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
                /* Because of generic sharing */
@@ -350,6 +351,7 @@ type_to_llvm_type (EmitContext *ctx, MonoType *t)
                if (!ltype) {
                        int i, size;
                        LLVMTypeRef *eltypes;
+                       char *name;
 
                        size = get_vtype_size (t);
 
@@ -357,8 +359,9 @@ type_to_llvm_type (EmitContext *ctx, MonoType *t)
                        for (i = 0; i < size; ++i)
                                eltypes [i] = LLVMInt8Type ();
 
-                       /* We couldn't name these types since LLVM uses structural type equality */
-                       ltype = LLVMStructType (eltypes, size, FALSE);
+                       name = mono_type_full_name (&klass->byval_arg);
+                       ltype = LLVMStructCreateNamed (LLVMGetGlobalContext (), name);
+                       LLVMStructSetBody (ltype, eltypes, size, FALSE);
                        g_hash_table_insert (ctx->lmodule->llvm_types, klass, ltype);
                        g_free (eltypes);
                }
@@ -638,7 +641,7 @@ static const char*
 simd_op_to_intrins (int opcode)
 {
        switch (opcode) {
-#if defined(TARGET_X86) || defined(TARGET_AMD64)
+#ifdef MONO_ARCH_SIMD_INTRINSICS
        case OP_MINPD:
                return "llvm.x86.sse2.min.pd";
        case OP_MINPS:
@@ -727,16 +730,6 @@ simd_op_to_intrins (int opcode)
                return "llvm.x86.sse.rsqrt.ps";
        case OP_RCPPS:
                return "llvm.x86.sse.rcp.ps";
-       case OP_PCMPEQB:
-               return "llvm.x86.sse2.pcmpeq.b";
-       case OP_PCMPEQW:
-               return "llvm.x86.sse2.pcmpeq.w";
-       case OP_PCMPEQD:
-               return "llvm.x86.sse2.pcmpeq.d";
-       case OP_PCMPEQQ:
-               return "llvm.x86.sse41.pcmpeqq";
-       case OP_PCMPGTB:
-               return "llvm.x86.sse2.pcmpgt.b";
        case OP_CVTDQ2PD:
                return "llvm.x86.sse2.cvtdq2pd";
        case OP_CVTDQ2PS:
@@ -779,7 +772,7 @@ simd_op_to_intrins (int opcode)
 static LLVMTypeRef
 simd_op_to_llvm_type (int opcode)
 {
-#if defined(TARGET_X86) || defined(TARGET_AMD64)
+#ifdef MONO_ARCH_SIMD_INTRINSICS
        switch (opcode) {
        case OP_EXTRACT_R8:
        case OP_EXPAND_R8:
@@ -843,7 +836,12 @@ get_bb (EmitContext *ctx, MonoBasicBlock *bb)
        char bb_name [128];
 
        if (ctx->bblocks [bb->block_num].bblock == NULL) {
-               sprintf (bb_name, "BB%d", bb->block_num);
+               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);
+               } else {
+                       sprintf (bb_name, "BB%d", bb->block_num);
+               }
 
                ctx->bblocks [bb->block_num].bblock = LLVMAppendBasicBlock (ctx->lmethod, bb_name);
                ctx->bblocks [bb->block_num].end_bblock = ctx->bblocks [bb->block_num].bblock;
@@ -1061,7 +1059,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                param_types [pindex] = IntPtrType ();
                pindex ++;
        }
-       if (cinfo && cinfo->imt_arg && IS_LLVM_MONO_BRANCH) {
+       if (cinfo && cinfo->imt_arg) {
                if (sinfo)
                        sinfo->imt_arg_pindex = pindex;
                param_types [pindex] = IntPtrType ();
@@ -1173,7 +1171,7 @@ LLVMFunctionType1(LLVMTypeRef ReturnType,
  *
  *   Create an LLVM function type from the arguments.
  */
-static LLVMTypeRef 
+static G_GNUC_UNUSED LLVMTypeRef
 LLVMFunctionType2(LLVMTypeRef ReturnType,
                                  LLVMTypeRef ParamType1,
                                  LLVMTypeRef ParamType2,
@@ -1192,7 +1190,7 @@ LLVMFunctionType2(LLVMTypeRef ReturnType,
  *
  *   Create an LLVM function type from the arguments.
  */
-static LLVMTypeRef 
+static G_GNUC_UNUSED LLVMTypeRef
 LLVMFunctionType3(LLVMTypeRef ReturnType,
                                  LLVMTypeRef ParamType1,
                                  LLVMTypeRef ParamType2,
@@ -1277,9 +1275,6 @@ set_metadata_flag (LLVMValueRef v, const char *flag_name)
        LLVMValueRef md_arg;
        int md_kind;
        
-       if (!IS_LLVM_MONO_BRANCH)
-               return;
-
        md_kind = LLVMGetMDKindID (flag_name, strlen (flag_name));
        md_arg = LLVMMDString ("mono", 4);
        LLVMSetMetadata (v, md_kind, LLVMMDNode (&md_arg, 1));
@@ -1347,7 +1342,7 @@ emit_load (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, in
        LLVMValueRef args [16], res;
        LLVMTypeRef addr_type;
 
-       if (is_faulting && bb->region != -1 && IS_LLVM_MONO_BRANCH) {
+       if (is_faulting && bb->region != -1) {
                /*
                 * We handle loads which can fault by calling a mono specific intrinsic
                 * using an invoke, so they are handled properly inside try blocks.
@@ -1412,7 +1407,7 @@ emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, i
        const char *intrins_name;
        LLVMValueRef args [16];
 
-       if (is_faulting && bb->region != -1 && IS_LLVM_MONO_BRANCH) {
+       if (is_faulting && bb->region != -1) {
                switch (size) {
                case 1:
                        intrins_name = "llvm.mono.store.i8.p0i8";
@@ -1479,13 +1474,8 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
                MonoMethodSignature *throw_sig = mono_metadata_signature_alloc (mono_get_corlib (), 2);
                throw_sig->ret = &mono_get_void_class ()->byval_arg;
                throw_sig->params [0] = &mono_get_int32_class ()->byval_arg;
-               if (IS_LLVM_MONO_BRANCH) {
-                       icall_name = "llvm_throw_corlib_exception_abs_trampoline";
-                       throw_sig->params [1] = &mono_get_intptr_class ()->byval_arg;
-               } else {
-                       icall_name = "llvm_throw_corlib_exception_trampoline";
-                       throw_sig->params [1] = &mono_get_int32_class ()->byval_arg;
-               }
+               icall_name = "llvm_throw_corlib_exception_abs_trampoline";
+               throw_sig->params [1] = &mono_get_intptr_class ()->byval_arg;
                sig = sig_to_llvm_sig (ctx, throw_sig);
 
                if (ctx->cfg->compile_aot) {
@@ -1511,24 +1501,12 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
        else
                args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token, FALSE);
 
-       if (IS_LLVM_MONO_BRANCH) {
-               /*
-                * 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 (), "");
-               emit_call (ctx, bb, &builder, ctx->lmodule->throw_corlib_exception, args, 2);
-       } else {
-               /*
-                * FIXME: The offset is 0, this is only a problem if the code is inside a clause,
-                * otherwise only the line numbers in stack traces are incorrect.
-                */
-               if (bb->region != -1 && !IS_LLVM_MONO_BRANCH)
-                       LLVM_FAILURE (ctx, "system-ex-in-region");
-
-               args [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
-               emit_call (ctx, bb, &builder, ctx->lmodule->throw_corlib_exception, args, 2);
-       }
+       /*
+        * 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 (), "");
+       emit_call (ctx, bb, &builder, ctx->lmodule->throw_corlib_exception, args, 2);
 
        LLVMBuildUnreachable (builder);
 
@@ -1539,9 +1517,6 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
 
        ctx->ex_index ++;
        return;
-
- FAILURE:
-       return;
 }
 
 /*
@@ -1842,11 +1817,11 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        LLVMValueRef *addresses = ctx->addresses;
        MonoCallInst *call = (MonoCallInst*)ins;
        MonoMethodSignature *sig = call->signature;
-       LLVMValueRef callee, lcall;
+       LLVMValueRef callee = NULL, lcall;
        LLVMValueRef *args;
        LLVMCallInfo *cinfo;
        GSList *l;
-       int i, len;
+       int i, len, nargs;
        gboolean vretaddr;
        LLVMTypeRef llvm_sig;
        gpointer target;
@@ -1857,18 +1832,6 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        if (call->signature->call_convention != MONO_CALL_DEFAULT)
                LLVM_FAILURE (ctx, "non-default callconv");
 
-       if (call->rgctx_arg_reg && !IS_LLVM_MONO_BRANCH)
-               LLVM_FAILURE (ctx, "rgctx reg in call");
-
-       if (call->rgctx_reg && !IS_LLVM_MONO_BRANCH) {
-               /*
-                * It might be possible to support this by creating a static rgctx trampoline, but
-                * common_call_trampoline () would patch callsites to call the trampoline, which
-                * would be incorrect if the rgctx arg is computed dynamically.
-                */
-               LLVM_FAILURE (ctx, "rgctx reg");
-       }
-
        cinfo = call->cinfo;
        if (call->rgctx_arg_reg)
                cinfo->rgctx_arg = TRUE;
@@ -1969,30 +1932,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                g_assert (ins->inst_offset % size == 0);
                index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
 
-               /*
-                * When using the llvm mono branch, we can support IMT directly, otherwise
-                * we need to call a trampoline.
-                */
-               if (call->method && call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE && !IS_LLVM_MONO_BRANCH) {
-#ifdef MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE
-                       if (cfg->compile_aot) {
-                               MonoJumpInfoImtTramp *imt_tramp = g_new0 (MonoJumpInfoImtTramp, 1);
-                               imt_tramp->method = call->method;
-                               imt_tramp->vt_offset = call->inst.inst_offset;
-
-                               callee = get_plt_entry (ctx, llvm_sig, MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE, imt_tramp);
-                       } else {
-                               callee = LLVMAddFunction (module, "", llvm_sig);
-                               target = mono_create_llvm_imt_trampoline (cfg->domain, call->method, call->inst.inst_offset);
-                               LLVMAddGlobalMapping (ee, callee, target);
-                       }
-#else
-                       /* No support for passing the IMT argument */
-                       LLVM_FAILURE (ctx, "imt");
-#endif
-               } else {
-                       callee = convert (ctx, LLVMBuildLoad (builder, LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (LLVMPointerType (IntPtrType (), 0), 0)), &index, 1, ""), ""), LLVMPointerType (llvm_sig, 0));
-               }
+               callee = convert (ctx, LLVMBuildLoad (builder, LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (LLVMPointerType (IntPtrType (), 0), 0)), &index, 1, ""), ""), LLVMPointerType (llvm_sig, 0));
        } else if (calli) {
                callee = convert (ctx, values [ins->sreg1], LLVMPointerType (llvm_sig, 0));
        } else {
@@ -2003,25 +1943,27 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        /* 
         * Collect and convert arguments
         */
-       len = sizeof (LLVMValueRef) * ((sig->param_count * 2) + sig->hasthis + vretaddr + call->rgctx_reg);
+       nargs = (sig->param_count * 2) + sig->hasthis + vretaddr + call->rgctx_reg + call->imt_arg_reg;
+       len = sizeof (LLVMValueRef) * nargs;
        args = alloca (len);
        memset (args, 0, len);
        l = call->out_ireg_args;
 
-       if (IS_LLVM_MONO_BRANCH) {
-               if (call->rgctx_arg_reg) {
-                       g_assert (values [call->rgctx_arg_reg]);
-                       args [sinfo.rgctx_arg_pindex] = values [call->rgctx_arg_reg];
-               }
-               if (call->imt_arg_reg) {
-                       g_assert (values [call->imt_arg_reg]);
-                       args [sinfo.imt_arg_pindex] = values [call->imt_arg_reg];
-               }
+       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];
+       }
+       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];
        }
 
        if (vretaddr) {
                if (!addresses [call->inst.dreg])
                        addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+               g_assert (sinfo.vret_arg_pindex < nargs);
                args [sinfo.vret_arg_pindex] = LLVMBuildPtrToInt (builder, addresses [call->inst.dreg], IntPtrType (), "");
        }
 
@@ -2149,10 +2091,11 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
        BBInfo *bblocks = ctx->bblocks;
        MonoInst *ins;
        LLVMBasicBlockRef cbb;
-       LLVMBuilderRef builder;
+       LLVMBuilderRef builder, starting_builder;
        gboolean has_terminator;
        LLVMValueRef v;
        LLVMValueRef lhs, rhs;
+       int nins = 0;
 
        cbb = get_bb (ctx, bb);
        builder = create_builder (ctx);
@@ -2165,7 +2108,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
        if (bb->flags & BB_EXCEPTION_HANDLER) {
                LLVMTypeRef i8ptr;
-               LLVMValueRef eh_selector, eh_exception, personality, args [4];
+               LLVMValueRef personality;
                LLVMBasicBlockRef target_bb;
                MonoInst *exvar;
                static gint32 mapping_inited;
@@ -2184,7 +2127,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        LLVM_FAILURE (ctx, "handler without invokes");
                }
 
-               eh_selector = LLVMGetNamedFunction (module, eh_selector_name);
+               // <resultval> = landingpad <somety> personality <type> <pers_fn> <clause>+
 
                if (cfg->compile_aot) {
                        /* Use a dummy personality function */
@@ -2219,6 +2162,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                         * http://llvm.org/bugs/show_bug.cgi?id=6102
                         */
                        //LLVM_FAILURE (ctx, "aot+clauses");
+#ifdef TARGET_ARM
+                       // test_0_invalid_unbox_arrays () fails
+                       LLVM_FAILURE (ctx, "aot+clauses");
+#endif
                } else {
                        /*
                         * After the cfg mempool is freed, the type info will point to stale memory,
@@ -2233,22 +2180,28 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        LLVMAddGlobalMapping (ee, type_info, ti);
                }
 
-               args [0] = LLVMConstNull (i8ptr);
-               args [1] = LLVMConstBitCast (personality, i8ptr);
-               args [2] = type_info;
-               LLVMBuildCall (builder, eh_selector, args, 3, "");
+               {
+                       LLVMTypeRef members [2], ret_type;
+                       LLVMValueRef landing_pad;
+
+                       members [0] = i8ptr;
+                       members [1] = LLVMInt32Type ();
+                       ret_type = LLVMStructType (members, 2, FALSE);
+
+                       landing_pad = LLVMBuildLandingPad (builder, ret_type, personality, 1, "");
+                       LLVMAddClause (landing_pad, type_info);
 
-               /* Store the exception into the exvar */
-               if (bb->in_scount == 1) {
-                       g_assert (bb->in_scount == 1);
-                       exvar = bb->in_stack [0];
+                       /* Store the exception into the exvar */
+                       if (bb->in_scount == 1) {
+                               g_assert (bb->in_scount == 1);
+                               exvar = bb->in_stack [0];
 
-                       eh_exception = LLVMGetNamedFunction (module, "llvm.eh.exception");
+                               // FIXME: This is shared with filter clauses ?
+                               g_assert (!values [exvar->dreg]);
 
-                       // FIXME: This is shared with filter clauses ?
-                       g_assert (!values [exvar->dreg]);
-                       values [exvar->dreg] = LLVMBuildCall (builder, eh_exception, NULL, 0, "");
-                       emit_volatile_store (ctx, exvar->dreg);
+                               values [exvar->dreg] = LLVMBuildExtractValue (builder, landing_pad, 0, "ex_obj");
+                               emit_volatile_store (ctx, exvar->dreg);
+                       }
                }
 
                /* Start a new bblock which CALL_HANDLER can branch to */
@@ -2264,11 +2217,18 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
        }
 
        has_terminator = FALSE;
+       starting_builder = builder;
        for (ins = bb->code; ins; ins = ins->next) {
                const char *spec = LLVM_INS_INFO (ins->opcode);
                char *dname = NULL;
                char dname_buf [128];
 
+               nins ++;
+               if (nins > 5000 && builder == starting_builder) {
+                       /* some steps in llc are non-linear in the size of basic blocks, see #5714 */
+                       LLVM_FAILURE (ctx, "basic block too long");
+               }
+
                if (has_terminator)
                        /* There could be instructions after a terminator, skip them */
                        break;
@@ -2814,7 +2774,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        break;
                case OP_INOT: {
                        guint32 v = 0xffffffff;
-                       values [ins->dreg] = LLVMBuildXor (builder, LLVMConstInt (LLVMInt32Type (), v, FALSE), lhs, dname);
+                       values [ins->dreg] = LLVMBuildXor (builder, LLVMConstInt (LLVMInt32Type (), v, FALSE), convert (ctx, lhs, LLVMInt32Type ()), dname);
                        break;
                }
                case OP_LNOT: {
@@ -3080,7 +3040,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                }
 
                case OP_CHECK_THIS:
-                       emit_load (ctx, bb, &builder, sizeof (gpointer), convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "", TRUE);
+                       emit_load (ctx, bb, &builder, sizeof (gpointer), convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE);
                        break;
                case OP_OUTARG_VTRETADDR:
                        break;
@@ -3195,14 +3155,14 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                         */
                        LLVM_FAILURE (ctx, "sqrt");
 #endif
-                       args [0] = lhs;
+                       args [0] = convert (ctx, lhs, LLVMDoubleType ());
                        values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.sqrt.f64"), args, 1, dname);
                        break;
                }
                case OP_ABS: {
                        LLVMValueRef args [1];
 
-                       args [0] = lhs;
+                       args [0] = convert (ctx, lhs, LLVMDoubleType ());
                        values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "fabs"), args, 1, dname);
                        break;
                }
@@ -3251,7 +3211,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt32Type (), 0));
                        args [1] = rhs;
-                       values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.atomic.swap.i32.p0i32"), args, 2, dname);
+
+                       values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
                        break;
                }
                case OP_ATOMIC_EXCHANGE_I8: {
@@ -3261,7 +3222,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt64Type (), 0));
                        args [1] = convert (ctx, rhs, LLVMInt64Type ());
-                       values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.atomic.swap.i64.p0i64"), args, 2, 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: {
@@ -3271,7 +3232,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt32Type (), 0));
                        args [1] = rhs;
-                       values [ins->dreg] = LLVMBuildAdd (builder, LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.atomic.load.add.i32.p0i32"), args, 2, ""), args [1], dname);
+                       values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
                        break;
                }
                case OP_ATOMIC_ADD_NEW_I8: {
@@ -3281,21 +3242,18 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt64Type (), 0));
                        args [1] = convert (ctx, rhs, LLVMInt64Type ());
-                       values [ins->dreg] = LLVMBuildAdd (builder, LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.atomic.load.add.i64.p0i64"), args, 2, ""), args [1], dname);
+                       values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
                        break;
                }
                case OP_ATOMIC_CAS_I4:
                case OP_ATOMIC_CAS_I8: {
                        LLVMValueRef args [3];
                        LLVMTypeRef t;
-                       const char *intrins;
                                
                        if (ins->opcode == OP_ATOMIC_CAS_I4) {
                                t = LLVMInt32Type ();
-                               intrins = "llvm.atomic.cmp.swap.i32.p0i32";
                        } else {
                                t = LLVMInt64Type ();
-                               intrins = "llvm.atomic.cmp.swap.i64.p0i64";
                        }
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
@@ -3303,37 +3261,23 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        args [1] = convert (ctx, values [ins->sreg3], t);
                        /* new value */
                        args [2] = convert (ctx, values [ins->sreg2], t);
-                       values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, intrins), args, 3, dname);
+                       values [ins->dreg] = mono_llvm_build_cmpxchg (builder, args [0], args [1], args [2]);
                        break;
                }
                case OP_MEMORY_BARRIER: {
-                       LLVMValueRef args [5];
-
-#ifdef TARGET_ARM
-                       /* Not yet supported by llc on arm */
-                       LLVM_FAILURE (ctx, "memory-barrier+arm");
-#endif
-
-                       for (i = 0; i < 5; ++i)
-                               args [i] = LLVMConstInt (LLVMInt1Type (), TRUE, TRUE);
-
-                       LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.memory.barrier"), args, 5, "");
+                       mono_llvm_build_fence (builder);
                        break;
                }
                case OP_RELAXED_NOP: {
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
-                       if (IS_LLVM_MONO_BRANCH)
-                               emit_call (ctx, bb, &builder, LLVMGetNamedFunction (ctx->module, "llvm.x86.sse2.pause"), NULL, 0);
-                       else
-                               /* No way to get LLVM to emit this */
-                               LLVM_FAILURE (ctx, "relaxed_nop");
+                       emit_call (ctx, bb, &builder, LLVMGetNamedFunction (ctx->module, "llvm.x86.sse2.pause"), NULL, 0);
                        break;
 #else
                        break;
 #endif
                }
                case OP_TLS_GET: {
-#if defined(TARGET_AMD64) || defined(TARGET_X86)
+#if (defined(TARGET_AMD64) || defined(TARGET_X86)) && defined(__linux__)
 #ifdef TARGET_AMD64
                        // 257 == FS segment register
                        LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 257);
@@ -3417,7 +3361,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_LOADV_MEMBASE:
                case OP_VMOVE: {
                        MonoClass *klass = ins->klass;
-                       LLVMValueRef src, dst, args [5];
+                       LLVMValueRef src = NULL, dst, args [5];
                        gboolean done = FALSE;
 
                        if (!klass) {
@@ -3488,7 +3432,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        /* 
                         * SIMD
                         */
-#if defined(TARGET_X86) || defined(TARGET_AMD64)
+#ifdef MONO_ARCH_SIMD_INTRINSICS
                case OP_XZERO: {
                        values [ins->dreg] = LLVMConstNull (type_to_llvm_type (ctx, &ins->klass->byval_arg));
                        break;
@@ -3559,7 +3503,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ORPD:
                case OP_XORPD: {
                        LLVMTypeRef t, rt;
-                       LLVMValueRef v;
+                       LLVMValueRef v = NULL;
 
                        switch (ins->opcode) {
                        case OP_ANDPS:
@@ -3632,11 +3576,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_PSUBW_SAT_UN:
                case OP_PAVGB_UN:
                case OP_PAVGW_UN:
-               case OP_PCMPEQB:
-               case OP_PCMPEQW:
-               case OP_PCMPEQD:
-               case OP_PCMPEQQ:
-               case OP_PCMPGTB:
                case OP_PACKW:
                case OP_PACKD:
                case OP_PACKW_UN:
@@ -3651,6 +3590,17 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, simd_op_to_intrins (ins->opcode)), args, 2, dname);
                        break;
                }
+               case OP_PCMPEQB:
+               case OP_PCMPEQW:
+               case OP_PCMPEQD:
+               case OP_PCMPEQQ: {
+                       values [ins->dreg] = LLVMBuildSExt (builder, LLVMBuildICmp (builder, LLVMIntEQ, lhs, rhs, ""), LLVMTypeOf (lhs), "");
+                       break;
+               }
+               case OP_PCMPGTB: {
+                       values [ins->dreg] = LLVMBuildSExt (builder, LLVMBuildICmp (builder, LLVMIntSGT, lhs, rhs, ""), LLVMTypeOf (lhs), "");
+                       break;
+               }
                case OP_EXTRACT_R8:
                case OP_EXTRACT_I8:
                case OP_EXTRACT_I4:
@@ -3809,7 +3759,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_PSHUFLEW_LOW:
                case OP_PSHUFLEW_HIGH: {
                        int mask [16];
-                       LLVMValueRef v1 = NULL, v2 = NULL, mask_values [4];
+                       LLVMValueRef v1 = NULL, v2 = NULL, mask_values [16];
                        int i, mask_size = 0;
                        int imask = ins->inst_c0;
        
@@ -4166,24 +4116,16 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 void
 mono_llvm_check_method_supported (MonoCompile *cfg)
 {
-       /*
        MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
        int i;
-       */
-
-       if (cfg->generic_sharing_context && !IS_LLVM_MONO_BRANCH) {
-               /* No way to obtain location info for this/rgctx */
-               cfg->exception_message = g_strdup ("gshared");
-               cfg->disable_llvm = TRUE;
-       }
 
        if (cfg->method->save_lmf) {
                cfg->exception_message = g_strdup ("lmf");
                cfg->disable_llvm = TRUE;
        }
 
-#if 0
+#if 1
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
                
@@ -4303,12 +4245,8 @@ mono_llvm_emit_method (MonoCompile *cfg)
        ctx->linfo = linfo;
        CHECK_FAILURE (ctx);
 
-       if (cfg->rgctx_var) {
-               if (IS_LLVM_MONO_BRANCH)
-                       linfo->rgctx_arg = TRUE;
-               else
-                       LLVM_FAILURE (ctx, "rgctx arg");
-       }
+       if (cfg->rgctx_var)
+               linfo->rgctx_arg = TRUE;
        method_type = sig_to_llvm_sig_full (ctx, sig, linfo, &sinfo);
        CHECK_FAILURE (ctx);
 
@@ -4326,7 +4264,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
 #endif
        LLVMSetLinkage (method, LLVMPrivateLinkage);
 
-       LLVMAddFunctionAttr (method, LLVMUWTableAttribute);
+       LLVMAddFunctionAttr (method, LLVMUWTable);
 
        if (cfg->compile_aot) {
                LLVMSetLinkage (method, LLVMInternalLinkage);
@@ -4526,7 +4464,9 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        if (ctx->unreachable [node->in_bb->block_num])
                                continue;
 
-                       g_assert (values [sreg1]);
+                       if (!values [sreg1])
+                               /* Can happen with values in EH clauses */
+                               LLVM_FAILURE (ctx, "incoming phi sreg1");
 
                        if (phi->opcode == OP_VPHI) {
                                g_assert (LLVMTypeOf (ctx->addresses [sreg1]) == LLVMTypeOf (values [phi->dreg]));
@@ -4661,15 +4601,19 @@ mono_llvm_emit_call (MonoCompile *cfg, MonoCallInst *call)
                /* Simply remember the arguments */
                switch (ainfo->storage) {
                case LLVMArgInIReg:
-                       MONO_INST_NEW (cfg, ins, OP_MOVE);
-                       ins->dreg = mono_alloc_ireg (cfg);
-                       ins->sreg1 = in->dreg;
-                       break;
-               case LLVMArgInFPReg:
-                       MONO_INST_NEW (cfg, ins, OP_FMOVE);
-                       ins->dreg = mono_alloc_freg (cfg);
+               case LLVMArgInFPReg: {
+                       MonoType *t = (sig->hasthis && i == 0) ? &mono_get_intptr_class ()->byval_arg : sig->params [i - sig->hasthis];
+
+                       if (!t->byref && (t->type == MONO_TYPE_R8 || t->type == MONO_TYPE_R4)) {
+                               MONO_INST_NEW (cfg, ins, OP_FMOVE);
+                               ins->dreg = mono_alloc_freg (cfg);
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = mono_alloc_ireg (cfg);
+                       }
                        ins->sreg1 = in->dreg;
                        break;
+               }
                case LLVMArgVtypeByVal:
                case LLVMArgVtypeInReg:
                        MONO_INST_NEW (cfg, ins, OP_LLVM_OUTARG_VT);
@@ -4798,6 +4742,27 @@ exception_cb (void *data)
        g_free (type_info);
 }
 
+static char*
+dlsym_cb (const char *name, void **symbol)
+{
+       MonoDl *current;
+       char *err;
+
+       err = NULL;
+       if (!strcmp (name, "__bzero")) {
+               *symbol = (void*)bzero;
+       } else {
+               current = mono_dl_open (NULL, 0, NULL);
+               g_assert (current);
+
+               err = mono_dl_symbol (current, name, symbol);
+       }
+#ifdef MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK
+       *symbol = (char*)mono_arch_create_llvm_native_thunk (mono_domain_get (), (guint8*)(*symbol));
+#endif
+       return err;
+}
+
 static inline void
 AddFunc (LLVMModuleRef module, const char *name, LLVMTypeRef ret_type, LLVMTypeRef *param_types, int nparams)
 {
@@ -4852,18 +4817,6 @@ add_intrinsics (LLVMModuleRef module)
                LLVMAddFunction (module, "fabs", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
        }
 
-       {
-               LLVMTypeRef membar_params [] = { LLVMInt1Type (), LLVMInt1Type (), LLVMInt1Type (), LLVMInt1Type (), LLVMInt1Type () };
-
-               LLVMAddFunction (module, "llvm.atomic.swap.i32.p0i32", LLVMFunctionType2 (LLVMInt32Type (), LLVMPointerType (LLVMInt32Type (), 0), LLVMInt32Type (), FALSE));
-               LLVMAddFunction (module, "llvm.atomic.swap.i64.p0i64", LLVMFunctionType2 (LLVMInt64Type (), LLVMPointerType (LLVMInt64Type (), 0), LLVMInt64Type (), FALSE));
-               LLVMAddFunction (module, "llvm.atomic.load.add.i32.p0i32", LLVMFunctionType2 (LLVMInt32Type (), LLVMPointerType (LLVMInt32Type (), 0), LLVMInt32Type (), FALSE));
-               LLVMAddFunction (module, "llvm.atomic.load.add.i64.p0i64", LLVMFunctionType2 (LLVMInt64Type (), LLVMPointerType (LLVMInt64Type (), 0), LLVMInt64Type (), FALSE));
-               LLVMAddFunction (module, "llvm.atomic.cmp.swap.i32.p0i32", LLVMFunctionType3 (LLVMInt32Type (), LLVMPointerType (LLVMInt32Type (), 0), LLVMInt32Type (), LLVMInt32Type (), FALSE));
-               LLVMAddFunction (module, "llvm.atomic.cmp.swap.i64.p0i64", LLVMFunctionType3 (LLVMInt64Type (), LLVMPointerType (LLVMInt64Type (), 0), LLVMInt64Type (), LLVMInt64Type (), FALSE));
-               LLVMAddFunction (module, "llvm.memory.barrier", LLVMFunctionType (LLVMVoidType (), membar_params, 5, FALSE));
-       }
-
        {
                LLVMTypeRef ovf_res_i32 [] = { LLVMInt32Type (), LLVMInt1Type () };
                LLVMTypeRef ovf_params_i32 [] = { LLVMInt32Type (), LLVMInt32Type () };
@@ -4905,13 +4858,8 @@ add_intrinsics (LLVMModuleRef module)
 
                arg_types [0] = LLVMPointerType (LLVMInt8Type (), 0);
                arg_types [1] = LLVMPointerType (LLVMInt8Type (), 0);
-               eh_selector_name = "llvm.eh.selector";
                ret_type = LLVMInt32Type ();
 
-               LLVMAddFunction (module, eh_selector_name, LLVMFunctionType (ret_type, arg_types, 2, TRUE));
-
-               LLVMAddFunction (module, "llvm.eh.exception", LLVMFunctionType (LLVMPointerType (LLVMInt8Type (), 0), NULL, 0, FALSE));
-
                LLVMAddFunction (module, "mono_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
 
                LLVMAddFunction (module, "llvm_resume_unwind_trampoline", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
@@ -4919,7 +4867,7 @@ add_intrinsics (LLVMModuleRef module)
 
        /* SSE intrinsics */
        {
-               LLVMTypeRef ret_type, arg_types [2];
+               LLVMTypeRef ret_type, arg_types [16];
 
                /* Binary ops */
                ret_type = type_to_simd_type (MONO_TYPE_I4);
@@ -4927,7 +4875,6 @@ add_intrinsics (LLVMModuleRef module)
                arg_types [1] = ret_type;
                AddFunc (module, "llvm.x86.sse41.pminud", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse41.pmaxud", ret_type, arg_types, 2);
-               AddFunc (module, "llvm.x86.sse2.pcmpeq.d", ret_type, arg_types, 2);
 
                ret_type = type_to_simd_type (MONO_TYPE_I2);
                arg_types [0] = ret_type;
@@ -4935,7 +4882,6 @@ add_intrinsics (LLVMModuleRef module)
                AddFunc (module, "llvm.x86.sse41.pminuw", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.pmins.w", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse41.pmaxuw", ret_type, arg_types, 2);
-               AddFunc (module, "llvm.x86.sse2.pcmpeq.w", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.padds.w", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.psubs.w", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.paddus.w", ret_type, arg_types, 2);
@@ -4949,19 +4895,12 @@ add_intrinsics (LLVMModuleRef module)
                arg_types [1] = ret_type;
                AddFunc (module, "llvm.x86.sse2.pminu.b", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.pmaxu.b", ret_type, arg_types, 2);
-               AddFunc (module, "llvm.x86.sse2.pcmpeq.b", ret_type, arg_types, 2);
-               AddFunc (module, "llvm.x86.sse2.pcmpgt.b", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.padds.b", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.psubs.b", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.paddus.b", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.psubus.b", ret_type, arg_types, 2);
                AddFunc (module, "llvm.x86.sse2.pavg.b", ret_type, arg_types, 2);
 
-               ret_type = type_to_simd_type (MONO_TYPE_I8);
-               arg_types [0] = ret_type;
-               arg_types [1] = ret_type;
-               AddFunc (module, "llvm.x86.sse41.pcmpeqq", ret_type, arg_types, 2);
-
                ret_type = type_to_simd_type (MONO_TYPE_R8);
                arg_types [0] = ret_type;
                arg_types [1] = ret_type;
@@ -5070,12 +5009,10 @@ add_intrinsics (LLVMModuleRef module)
                AddFunc (module, "llvm.x86.sse2.pmovmskb.128", ret_type, arg_types, 1);
        }
 
-       if (IS_LLVM_MONO_BRANCH) {
-               AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
-       }
+       AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
 
        /* Load/Store intrinsics */
-       if (IS_LLVM_MONO_BRANCH) {
+       {
                LLVMTypeRef arg_types [5];
                int i;
                char name [128];
@@ -5100,7 +5037,7 @@ add_intrinsics (LLVMModuleRef module)
 void
 mono_llvm_init (void)
 {
-       mono_native_tls_alloc (current_cfg_tls_id, NULL);
+       mono_native_tls_alloc (&current_cfg_tls_id, NULL);
 }
 
 static void
@@ -5120,7 +5057,7 @@ init_jit_module (void)
 
        jit_module.module = LLVMModuleCreateWithName ("mono");
 
-       ee = mono_llvm_create_ee (LLVMCreateModuleProviderForExistingModule (jit_module.module), alloc_cb, emitted_cb, exception_cb);
+       ee = mono_llvm_create_ee (LLVMCreateModuleProviderForExistingModule (jit_module.module), alloc_cb, emitted_cb, exception_cb, dlsym_cb);
 
        add_intrinsics (jit_module.module);