[jit] Cleanup the usage of DISABLE_JIT a bit so it encompasses the whole mini-codegen...
[mono.git] / mono / mini / mini-llvm.c
index bc7b1765b71905c6bc162749d11c927f4618ff05..98802978e85ef78a054087c0e0fe85fe7d106ce3 100644 (file)
@@ -6,7 +6,8 @@
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mini.h"
+#include "config.h"
+
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/debug-mono-symfile.h>
 #include <mono/metadata/mempool-internals.h>
@@ -33,6 +34,8 @@
 #include "aot-compiler.h"
 #include "mini-llvm.h"
 
+#ifndef DISABLE_JIT
+
 #ifdef __MINGW32__
 
 #include <stddef.h>
@@ -148,6 +151,7 @@ typedef struct {
        LLVMValueRef rgctx_arg;
        LLVMValueRef this_arg;
        LLVMTypeRef *vreg_types;
+       gboolean *is_vphi;
        LLVMTypeRef method_type;
        LLVMBasicBlockRef init_bb, inited_bb;
        gboolean *is_dead;
@@ -170,6 +174,7 @@ typedef struct {
        GPtrArray *bblock_list;
        char *method_name;
        GHashTable *jit_callees;
+       LLVMValueRef long_bb_break_var;
 } EmitContext;
 
 typedef struct {
@@ -813,14 +818,6 @@ simd_op_to_intrins (int opcode)
                return "llvm.x86.sse2.min.pd";
        case OP_MINPS:
                return "llvm.x86.sse.min.ps";
-       case OP_PMIND_UN:
-               return "llvm.x86.sse41.pminud";
-       case OP_PMINW_UN:
-               return "llvm.x86.sse41.pminuw";
-       case OP_PMINB_UN:
-               return "llvm.x86.sse2.pminu.b";
-       case OP_PMINW:
-               return "llvm.x86.sse2.pmins.w";
        case OP_MAXPD:
                return "llvm.x86.sse2.max.pd";
        case OP_MAXPS:
@@ -833,12 +830,6 @@ simd_op_to_intrins (int opcode)
                return "llvm.x86.sse3.hsub.pd";
        case OP_HSUBPS:
                return "llvm.x86.sse3.hsub.ps";
-       case OP_PMAXD_UN:
-               return "llvm.x86.sse41.pmaxud";
-       case OP_PMAXW_UN:
-               return "llvm.x86.sse41.pmaxuw";
-       case OP_PMAXB_UN:
-               return "llvm.x86.sse2.pmaxu.b";
        case OP_ADDSUBPS:
                return "llvm.x86.sse3.addsub.ps";
        case OP_ADDSUBPD:
@@ -913,10 +904,6 @@ simd_op_to_intrins (int opcode)
                return "llvm.x86.sse2.cvttpd2dq";
        case OP_CVTTPS2DQ:
                return "llvm.x86.sse2.cvttps2dq";
-       case OP_COMPPS:
-               return "llvm.x86.sse.cmp.ps";
-       case OP_COMPPD:
-               return "llvm.x86.sse2.cmp.pd";
        case OP_PACKW:
                return "llvm.x86.sse2.packsswb.128";
        case OP_PACKD:
@@ -1156,8 +1143,19 @@ static LLVMValueRef
 emit_volatile_load (EmitContext *ctx, int vreg)
 {
        MonoType *t;
+       LLVMValueRef v;
 
-       LLVMValueRef v = LLVMBuildLoad (ctx->builder, ctx->addresses [vreg], "");
+#ifdef TARGET_ARM64
+       // FIXME: This hack is required because we pass the rgctx in a callee saved
+       // register on arm64 (x15), and llvm might keep the value in that register
+       // even through the register is marked as 'reserved' inside llvm.
+       if (ctx->cfg->rgctx_var && ctx->cfg->rgctx_var->dreg == vreg)
+               v = mono_llvm_build_load (ctx->builder, ctx->addresses [vreg], "", TRUE);
+       else
+               v = LLVMBuildLoad (ctx->builder, ctx->addresses [vreg], "");
+#else
+       v = LLVMBuildLoad (ctx->builder, ctx->addresses [vreg], "");
+#endif
        t = ctx->vreg_cli_types [vreg];
        if (t && !t->byref) {
                /* 
@@ -1590,18 +1588,17 @@ get_aotconst_typed (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data,
        MonoCompile *cfg;
        guint32 got_offset;
        LLVMValueRef indexes [2];
-       MonoJumpInfo *ji;
        LLVMValueRef got_entry_addr, load;
        LLVMBuilderRef builder = ctx->builder;
        char *name = NULL;
 
        cfg = ctx->cfg;
 
-       ji = g_new0 (MonoJumpInfo, 1);
-       ji->type = type;
-       ji->data.target = data;
+       MonoJumpInfo tmp_ji;
+       tmp_ji.type = type;
+       tmp_ji.data.target = data;
 
-       ji = mono_aot_patch_info_dup (ji);
+       MonoJumpInfo *ji = mono_aot_patch_info_dup (&tmp_ji);
 
        ji->next = cfg->patch_info;
        cfg->patch_info = ji;
@@ -1747,6 +1744,8 @@ get_handler_clause (MonoCompile *cfg, MonoBasicBlock *bb)
 static MonoExceptionClause *
 get_most_deep_clause (MonoCompile *cfg, EmitContext *ctx, MonoBasicBlock *bb)
 {
+       if (bb == cfg->bb_init)
+               return NULL;
        // Since they're sorted by nesting we just need
        // the first one that the bb is a member of
        for (int i = 0; i < cfg->header->num_clauses; i++) {
@@ -2423,7 +2422,7 @@ emit_get_method (MonoLLVMModule *module)
        LLVMBasicBlockRef entry_bb, fail_bb, bb, code_start_bb, code_end_bb;
        LLVMBasicBlockRef *bbs;
        LLVMTypeRef rtype;
-       LLVMBuilderRef builder;
+       LLVMBuilderRef builder = LLVMCreateBuilder ();
        char *name;
        int i;
 
@@ -2449,14 +2448,12 @@ emit_get_method (MonoLLVMModule *module)
        name = g_strdup_printf ("BB_CODE_START");
        code_start_bb = LLVMAppendBasicBlock (func, name);
        g_free (name);
-       builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, code_start_bb);
        LLVMBuildRet (builder, LLVMBuildBitCast (builder, module->code_start, rtype, ""));
 
        name = g_strdup_printf ("BB_CODE_END");
        code_end_bb = LLVMAppendBasicBlock (func, name);
        g_free (name);
-       builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, code_end_bb);
        LLVMBuildRet (builder, LLVMBuildBitCast (builder, module->code_end, rtype, ""));
 
@@ -2467,7 +2464,6 @@ emit_get_method (MonoLLVMModule *module)
                g_free (name);
                bbs [i] = bb;
 
-               builder = LLVMCreateBuilder ();
                LLVMPositionBuilderAtEnd (builder, bb);
 
                m = (LLVMValueRef)g_hash_table_lookup (module->idx_to_lmethod, GINT_TO_POINTER (i));
@@ -2478,11 +2474,9 @@ emit_get_method (MonoLLVMModule *module)
        }
 
        fail_bb = LLVMAppendBasicBlock (func, "FAIL");
-       builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, fail_bb);
        LLVMBuildRet (builder, LLVMConstNull (rtype));
 
-       builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, entry_bb);
 
        switch_ins = LLVMBuildSwitch (builder, LLVMGetParam (func, 0), fail_bb, 0);
@@ -2493,6 +2487,8 @@ emit_get_method (MonoLLVMModule *module)
        }
 
        mark_as_used (module, func);
+
+       LLVMDisposeBuilder (builder);
 }
 
 /*
@@ -2508,7 +2504,7 @@ emit_get_unbox_tramp (MonoLLVMModule *module)
        LLVMBasicBlockRef entry_bb, fail_bb, bb;
        LLVMBasicBlockRef *bbs;
        LLVMTypeRef rtype;
-       LLVMBuilderRef builder;
+       LLVMBuilderRef builder = LLVMCreateBuilder ();
        char *name;
        int i;
 
@@ -2534,18 +2530,15 @@ emit_get_unbox_tramp (MonoLLVMModule *module)
                g_free (name);
                bbs [i] = bb;
 
-               builder = LLVMCreateBuilder ();
                LLVMPositionBuilderAtEnd (builder, bb);
 
                LLVMBuildRet (builder, LLVMBuildBitCast (builder, m, rtype, ""));
        }
 
        fail_bb = LLVMAppendBasicBlock (func, "FAIL");
-       builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, fail_bb);
        LLVMBuildRet (builder, LLVMConstNull (rtype));
 
-       builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, entry_bb);
 
        switch_ins = LLVMBuildSwitch (builder, LLVMGetParam (func, 0), fail_bb, 0);
@@ -2558,6 +2551,7 @@ emit_get_unbox_tramp (MonoLLVMModule *module)
        }
 
        mark_as_used (module, func);
+       LLVMDisposeBuilder (builder);
 }
 
 /* Add a function to mark the beginning of LLVM code */
@@ -2577,6 +2571,7 @@ emit_llvm_code_start (MonoLLVMModule *module)
        builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, entry_bb);
        LLVMBuildRetVoid (builder);
+       LLVMDisposeBuilder (builder);
 }
 
 static LLVMValueRef
@@ -2650,6 +2645,7 @@ emit_init_icall_wrapper (MonoLLVMModule *module, const char *name, const char *i
        LLVMBuildRetVoid (builder);
 
        LLVMVerifyFunction(func, LLVMAbortProcessAction);
+       LLVMDisposeBuilder (builder);
        return func;
 }
 
@@ -2683,6 +2679,7 @@ emit_llvm_code_end (MonoLLVMModule *module)
        builder = LLVMCreateBuilder ();
        LLVMPositionBuilderAtEnd (builder, entry_bb);
        LLVMBuildRetVoid (builder);
+       LLVMDisposeBuilder (builder);
 }
 
 static void
@@ -2873,6 +2870,7 @@ emit_unbox_tramp (EmitContext *ctx, const char *method_name, LLVMTypeRef method_
                LLVMBuildRet (builder, call);
 
        g_hash_table_insert (ctx->module->idx_to_unbox_tramp, GINT_TO_POINTER (method_index), tramp);
+       LLVMDisposeBuilder (builder);
 }
 
 /*
@@ -3492,6 +3490,9 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
 
        lcall = emit_call (ctx, bb, &builder, callee, args, LLVMCountParamTypes (llvm_sig));
 
+       if (ins->opcode != OP_TAILCALL && LLVMGetInstructionOpcode (lcall) == LLVMCall)
+               mono_llvm_set_call_notail (lcall);
+
        /*
         * Modify cconv and parameter attributes to pass rgctx/imt correctly.
         */
@@ -3986,6 +3987,7 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
                        LLVMPositionBuilderAtEnd (builder2, entry_bb);
                        LLVMBuildRet (builder2, LLVMConstInt (LLVMInt32Type (), 0, FALSE));
                        ctx->module->personality = personality;
+                       LLVMDisposeBuilder (builder2);
                }
 #else
                static gint32 mapping_inited;
@@ -4158,13 +4160,36 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                if (nins > 1000) {
                        /*
                         * Some steps in llc are non-linear in the size of basic blocks, see #5714.
-                        * Start a new bblock. If the llvm optimization passes merge these, we
-                        * can work around that by doing a volatile load + cond branch from
-                        * localloc-ed memory.
+                        * Start a new bblock.
+                        * Prevent the bblocks to be merged by doing a volatile load + cond branch
+                        * from localloc-ed memory.
                         */
-                       //set_failure (ctx, "basic block too long");
+                       if (!cfg->llvm_only)
+                               ;//set_failure (ctx, "basic block too long");
+
+                       if (!ctx->long_bb_break_var) {
+                               ctx->long_bb_break_var = build_alloca_llvm_type_name (ctx, LLVMInt32Type (), 0, "long_bb_break");
+                               mono_llvm_build_store (ctx->alloca_builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), ctx->long_bb_break_var, TRUE, LLVM_BARRIER_NONE);
+                       }
+
                        cbb = gen_bb (ctx, "CONT_LONG_BB");
-                       LLVMBuildBr (ctx->builder, cbb);
+                       LLVMBasicBlockRef dummy_bb = gen_bb (ctx, "CONT_LONG_BB_DUMMY");
+
+                       LLVMValueRef load = mono_llvm_build_load (builder, ctx->long_bb_break_var, "", TRUE);
+                       /*
+                        * The long_bb_break_var is initialized to 0 in the prolog, so this branch will always go to 'cbb'
+                        * but llvm doesn't know that, so the branch is not going to be eliminated.
+                        */
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntEQ, load, LLVMConstInt (LLVMInt32Type (), 0, FALSE), "");
+
+                       LLVMBuildCondBr (builder, cmp, cbb, dummy_bb);
+
+                       /* Emit a dummy false bblock which does nothing but contains a volatile store so it cannot be eliminated */
+                       ctx->builder = builder = create_builder (ctx);
+                       LLVMPositionBuilderAtEnd (builder, dummy_bb);
+                       mono_llvm_build_store (builder, LLVMConstInt (LLVMInt32Type (), 1, FALSE), ctx->long_bb_break_var, TRUE, LLVM_BARRIER_NONE);
+                       LLVMBuildBr (builder, cbb);
+
                        ctx->builder = builder = create_builder (ctx);
                        LLVMPositionBuilderAtEnd (builder, cbb);
                        ctx->bblocks [bb->block_num].end_bblock = cbb;
@@ -5383,6 +5408,17 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildSelect (builder, v, lhs, rhs, dname);
                        break;
                }
+
+/*
+ * See the ARM64 comment in mono/utils/atomic.h for an explanation of why this
+ * hack is necessary (for now).
+ */
+#ifdef TARGET_ARM64
+#define ARM64_ATOMIC_FENCE_FIX mono_llvm_build_fence (builder, LLVM_BARRIER_SEQ)
+#else
+#define ARM64_ATOMIC_FENCE_FIX
+#endif
+
                case OP_ATOMIC_EXCHANGE_I4:
                case OP_ATOMIC_EXCHANGE_I8: {
                        LLVMValueRef args [2];
@@ -5398,7 +5434,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
                        args [1] = convert (ctx, rhs, t);
 
+                       ARM64_ATOMIC_FENCE_FIX;
                        values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
+                       ARM64_ATOMIC_FENCE_FIX;
                        break;
                }
                case OP_ATOMIC_ADD_I4:
@@ -5415,7 +5453,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
                        args [1] = convert (ctx, rhs, t);
+                       ARM64_ATOMIC_FENCE_FIX;
                        values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
+                       ARM64_ATOMIC_FENCE_FIX;
                        break;
                }
                case OP_ATOMIC_CAS_I4:
@@ -5433,7 +5473,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        args [1] = convert (ctx, values [ins->sreg3], t);
                        /* new value */
                        args [2] = convert (ctx, values [ins->sreg2], t);
+                       ARM64_ATOMIC_FENCE_FIX;
                        val = mono_llvm_build_cmpxchg (builder, args [0], args [1], args [2]);
+                       ARM64_ATOMIC_FENCE_FIX;
                        /* cmpxchg returns a pair */
                        values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, "");
                        break;
@@ -5474,7 +5516,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        addr = convert (ctx, addr, LLVMPointerType (t, 0));
 
+                       ARM64_ATOMIC_FENCE_FIX;
                        values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, lhs, dname, is_volatile, barrier);
+                       ARM64_ATOMIC_FENCE_FIX;
 
                        if (sext)
                                values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
@@ -5522,7 +5566,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
                        value = convert (ctx, values [ins->sreg1], t);
 
+                       ARM64_ATOMIC_FENCE_FIX;
                        emit_store_general (ctx, bb, &builder, size, value, addr, base, is_volatile, barrier);
+                       ARM64_ATOMIC_FENCE_FIX;
                        break;
                }
                case OP_RELAXED_NOP: {
@@ -5799,12 +5845,13 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        if (!var) {
                                LLVMValueRef indexes [16];
 
-                               LLVMValueRef name_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), strlen (name) + 1), "@OBJC_METH_VAR_NAME");
+                               LLVMValueRef name_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), strlen (name) + 1), "@OBJC_METH_VAR_NAME_");
                                LLVMSetInitializer (name_var, mono_llvm_create_constant_data_array ((const uint8_t*)name, strlen (name) + 1));
                                LLVMSetLinkage (name_var, LLVMPrivateLinkage);
                                LLVMSetSection (name_var, "__TEXT,__objc_methname,cstring_literals");
+                               mark_as_used (ctx->module, name_var);
 
-                               LLVMValueRef ref_var = LLVMAddGlobal (ctx->lmodule, LLVMPointerType (LLVMInt8Type (), 0), "@OBJC_SELECTOR_REFERENCES");
+                               LLVMValueRef ref_var = LLVMAddGlobal (ctx->lmodule, LLVMPointerType (LLVMInt8Type (), 0), "@OBJC_SELECTOR_REFERENCES_");
 
                                indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, 0);
                                indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, 0);
@@ -5813,6 +5860,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                LLVMSetExternallyInitialized (ref_var, TRUE);
                                LLVMSetSection (ref_var, "__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
                                LLVMSetAlignment (ref_var, sizeof (mgreg_t));
+                               mark_as_used (ctx->module, ref_var);
 
                                g_hash_table_insert (ctx->module->objc_selector_to_var, g_strdup (name), ref_var);
                                var = ref_var;
@@ -5942,19 +5990,31 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildBitCast (builder, v, rt, "");
                        break;
                }
+               case OP_PMIND_UN:
+               case OP_PMINW_UN:
+               case OP_PMINB_UN: {
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntULT, lhs, rhs, "");
+                       values [ins->dreg] = LLVMBuildSelect (builder, cmp, lhs, rhs, "");
+                       break;
+               }
+               case OP_PMAXD_UN:
+               case OP_PMAXW_UN:
+               case OP_PMAXB_UN: {
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntUGT, lhs, rhs, "");
+                       values [ins->dreg] = LLVMBuildSelect (builder, cmp, lhs, rhs, "");
+                       break;
+               }
+               case OP_PMINW: {
+                       LLVMValueRef cmp = LLVMBuildICmp (builder, LLVMIntSLT, lhs, rhs, "");
+                       values [ins->dreg] = LLVMBuildSelect (builder, cmp, lhs, rhs, "");
+                       break;
+               }
                case OP_MINPD:
                case OP_MINPS:
                case OP_MAXPD:
                case OP_MAXPS:
                case OP_ADDSUBPD:
                case OP_ADDSUBPS:
-               case OP_PMIND_UN:
-               case OP_PMINW_UN:
-               case OP_PMINB_UN:
-               case OP_PMINW:
-               case OP_PMAXD_UN:
-               case OP_PMAXW_UN:
-               case OP_PMAXB_UN:
                case OP_HADDPD:
                case OP_HADDPS:
                case OP_HSUBPD:
@@ -6070,6 +6130,33 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildInsertElement (builder, values [ins->sreg1], convert (ctx, values [ins->sreg2], LLVMDoubleType ()), LLVMConstInt (LLVMInt32Type (), ins->inst_c0, FALSE), dname);
                        break;
 
+#if 0
+                       // Requires a later llvm version
+               case OP_CVTDQ2PD: {
+                       LLVMValueRef indexes [16];
+
+                       indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+                       indexes [1] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+                       LLVMValueRef mask = LLVMConstVector (indexes, 2);
+                       LLVMValueRef shuffle = LLVMBuildShuffleVector (builder, lhs, LLVMConstNull (LLVMTypeOf (lhs)), mask, "");
+                       values [ins->dreg] = LLVMBuildSIToFP (builder, shuffle, LLVMVectorType (LLVMDoubleType (), 2), dname);
+                       break;
+               }
+               case OP_CVTPS2PD: {
+                       LLVMValueRef indexes [16];
+
+                       indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+                       indexes [1] = LLVMConstInt (LLVMInt32Type (), 1, FALSE);
+                       LLVMValueRef mask = LLVMConstVector (indexes, 2);
+                       LLVMValueRef shuffle = LLVMBuildShuffleVector (builder, lhs, LLVMConstNull (LLVMTypeOf (lhs)), mask, "");
+                       values [ins->dreg] = LLVMBuildFPExt (builder, shuffle, LLVMVectorType (LLVMDoubleType (), 2), dname);
+                       break;
+               }
+               case OP_CVTTPS2DQ:
+                       values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMVectorType (LLVMInt32Type (), 4), dname);
+                       break;
+#endif
+
                case OP_CVTDQ2PD:
                case OP_CVTDQ2PS:
                case OP_CVTPD2DQ:
@@ -6090,19 +6177,46 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), &v, 1, dname);
                        break;
                }
-
                case OP_COMPPS:
                case OP_COMPPD: {
-                       LLVMValueRef args [3];
+                       LLVMRealPredicate op;
 
-                       args [0] = lhs;
-                       args [1] = rhs;
-                       args [2] = LLVMConstInt (LLVMInt8Type (), ins->inst_c0, FALSE);
+                       switch (ins->inst_c0) {
+                       case SIMD_COMP_EQ:
+                               op = LLVMRealOEQ;
+                               break;
+                       case SIMD_COMP_LT:
+                               op = LLVMRealOLT;
+                               break;
+                       case SIMD_COMP_LE:
+                               op = LLVMRealOLE;
+                               break;
+                       case SIMD_COMP_UNORD:
+                               op = LLVMRealUNO;
+                               break;
+                       case SIMD_COMP_NEQ:
+                               op = LLVMRealUNE;
+                               break;
+                       case SIMD_COMP_NLT:
+                               op = LLVMRealUGE;
+                               break;
+                       case SIMD_COMP_NLE:
+                               op = LLVMRealUGT;
+                               break;
+                       case SIMD_COMP_ORD:
+                               op = LLVMRealORD;
+                               break;
+                       default:
+                               g_assert_not_reached ();
+                       }
 
-                       values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+                       LLVMValueRef cmp = LLVMBuildFCmp (builder, op, lhs, rhs, "");
+                       if (ins->opcode == OP_COMPPD)
+                               values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt64Type (), 2), ""), LLVMTypeOf (lhs), "");
+                       else
+                               values [ins->dreg] = LLVMBuildBitCast (builder, LLVMBuildSExt (builder, cmp, LLVMVectorType (LLVMInt32Type (), 4), ""), LLVMTypeOf (lhs), "");
                        break;
                }
-
                case OP_ICONV_TO_X:
                        /* This is only used for implementing shifts by non-immediate */
                        values [ins->dreg] = lhs;
@@ -6461,7 +6575,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                /* Convert the value to the type required by phi nodes */
                if (spec [MONO_INST_DEST] != ' ' && !MONO_IS_STORE_MEMBASE (ins) && ctx->vreg_types [ins->dreg]) {
-                       if (!values [ins->dreg])
+                       if (ctx->is_vphi [ins->dreg])
                                /* vtypes */
                                values [ins->dreg] = addresses [ins->dreg];
                        else
@@ -6610,6 +6724,7 @@ free_ctx (EmitContext *ctx)
        g_free (ctx->values);
        g_free (ctx->addresses);
        g_free (ctx->vreg_types);
+       g_free (ctx->is_vphi);
        g_free (ctx->vreg_cli_types);
        g_free (ctx->is_dead);
        g_free (ctx->unreachable);
@@ -6618,6 +6733,14 @@ free_ctx (EmitContext *ctx)
        g_hash_table_destroy (ctx->region_to_handler);
        g_hash_table_destroy (ctx->clause_to_handler);
        g_hash_table_destroy (ctx->jit_callees);
+
+       GHashTableIter iter;
+       g_hash_table_iter_init (&iter, ctx->method_to_callers);
+       while (g_hash_table_iter_next (&iter, NULL, (gpointer)&l))
+               g_slist_free (l);
+
+       g_hash_table_destroy (ctx->method_to_callers);
+
        g_free (ctx->method_name);
        g_ptr_array_free (ctx->bblock_list, TRUE);
 
@@ -6662,6 +6785,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->is_vphi = g_new0 (gboolean, cfg->next_vreg);
        ctx->vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg);
        ctx->phi_values = g_ptr_array_sized_new (256);
        /* 
@@ -7010,8 +7134,11 @@ emit_method_inner (EmitContext *ctx)
                                for (i = 0; i < ins->inst_phi_args [0]; i++) {
                                        int sreg1 = ins->inst_phi_args [i + 1];
                                        
-                                       if (sreg1 != -1)
+                                       if (sreg1 != -1) {
+                                               if (ins->opcode == OP_VPHI)
+                                                       ctx->is_vphi [sreg1] = TRUE;
                                                ctx->vreg_types [sreg1] = phi_type;
+                                       }
                                }
                                break;
                                }
@@ -7173,7 +7300,11 @@ emit_method_inner (EmitContext *ctx)
                ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index);
 
                // FIXME: beforefieldinit
-               if (ctx->has_got_access || mono_class_get_cctor (cfg->method->klass)) {
+               /*
+                * NATIVE_TO_MANAGED methods might be called on a thread not attached to the runtime, so they are initialized when loaded
+                * in load_method ().
+                */
+               if ((ctx->has_got_access || mono_class_get_cctor (cfg->method->klass)) && !(cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)) {
                        /*
                         * linkonce methods shouldn't have initialization,
                         * because they might belong to assemblies which
@@ -7714,11 +7845,6 @@ typedef enum {
        INTRINS_SSE_HADDPD,
        INTRINS_SSE_HSUBPD,
        INTRINS_SSE_ADDSUBPD,
-       INTRINS_SSE_PMINUD,
-       INTRINS_SSE_PMAXUD,
-       INTRINS_SSE_PMINUW,
-       INTRINS_SSE_PMINSW,
-       INTRINS_SSE_PMAXUW,
        INTRINS_SSE_PADDSW,
        INTRINS_SSE_PSUBSW,
        INTRINS_SSE_PADDUSW,
@@ -7726,8 +7852,6 @@ typedef enum {
        INTRINS_SSE_PAVGW,
        INTRINS_SSE_PMULHW,
        INTRINS_SSE_PMULHU,
-       INTRINS_SSE_PMINUB,
-       INTRINS_SSE_PMAXUB,
        INTRINS_SE_PADDSB,
        INTRINS_SSE_PSUBSB,
        INTRINS_SSE_PADDUSB,
@@ -7803,11 +7927,6 @@ static IntrinsicDesc intrinsics[] = {
        {INTRINS_SSE_HADDPD, "llvm.x86.sse3.hadd.pd"},
        {INTRINS_SSE_HSUBPD, "llvm.x86.sse3.hsub.pd"},
        {INTRINS_SSE_ADDSUBPD, "llvm.x86.sse3.addsub.pd"},
-       {INTRINS_SSE_PMINUD, "llvm.x86.sse41.pminud"},
-       {INTRINS_SSE_PMAXUD, "llvm.x86.sse41.pmaxud"},
-       {INTRINS_SSE_PMINUW, "llvm.x86.sse41.pminuw"},
-       {INTRINS_SSE_PMINSW, "llvm.x86.sse2.pmins.w"},
-       {INTRINS_SSE_PMAXUW, "llvm.x86.sse41.pmaxuw"},
        {INTRINS_SSE_PADDSW, "llvm.x86.sse2.padds.w"},
        {INTRINS_SSE_PSUBSW, "llvm.x86.sse2.psubs.w"},
        {INTRINS_SSE_PADDUSW, "llvm.x86.sse2.paddus.w"},
@@ -7815,8 +7934,6 @@ static IntrinsicDesc intrinsics[] = {
        {INTRINS_SSE_PAVGW, "llvm.x86.sse2.pavg.w"},
        {INTRINS_SSE_PMULHW, "llvm.x86.sse2.pmulh.w"},
        {INTRINS_SSE_PMULHU, "llvm.x86.sse2.pmulhu.w"},
-       {INTRINS_SSE_PMINUB, "llvm.x86.sse2.pminu.b"},
-       {INTRINS_SSE_PMAXUB, "llvm.x86.sse2.pmaxu.b"},
        {INTRINS_SE_PADDSB, "llvm.x86.sse2.padds.b"},
        {INTRINS_SSE_PSUBSB, "llvm.x86.sse2.psubs.b"},
        {INTRINS_SSE_PADDUSB, "llvm.x86.sse2.paddus.b"},
@@ -8022,13 +8139,6 @@ add_intrinsic (LLVMModuleRef module, int id)
                AddFunc (module, name, ret_type, arg_types, 2);
                break;
                /* SSE Binary ops */
-       case INTRINS_SSE_PMINUD:
-       case INTRINS_SSE_PMAXUD:
-               add_sse_binary (module, name, MONO_TYPE_I4);
-               break;
-       case INTRINS_SSE_PMINUW:
-       case INTRINS_SSE_PMINSW:
-       case INTRINS_SSE_PMAXUW:
        case INTRINS_SSE_PADDSW:
        case INTRINS_SSE_PSUBSW:
        case INTRINS_SSE_PADDUSW:
@@ -8052,8 +8162,6 @@ add_intrinsic (LLVMModuleRef module, int id)
        case INTRINS_SSE_ADDSUBPD:
                add_sse_binary (module, name, MONO_TYPE_R8);
                break;
-       case INTRINS_SSE_PMINUB:
-       case INTRINS_SSE_PMAXUB:
        case INTRINS_SE_PADDSB:
        case INTRINS_SSE_PSUBSB:
        case INTRINS_SSE_PADDUSB:
@@ -8126,11 +8234,6 @@ add_intrinsics (LLVMModuleRef module)
                AddFunc (module, "llvm_resume_unwind_trampoline", LLVMVoidType (), NULL, 0);
        }
 
-       /* SSE intrinsics */
-#if defined(TARGET_X86) || defined(TARGET_AMD64)
-
-#endif
-
        /* Load/Store intrinsics */
        {
                LLVMTypeRef arg_types [5];
@@ -8292,16 +8395,12 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix,
        module->llvm_only = llvm_only;
        /* The first few entries are reserved */
        module->max_got_offset = 16;
-       module->context = LLVMContextCreate ();
+       module->context = LLVMGetGlobalContext ();
 
        if (llvm_only)
                /* clang ignores our debug info because it has an invalid version */
                module->emit_dwarf = FALSE;
 
-#if LLVM_API_VERSION > 100
-       module->emit_dwarf = FALSE;
-#endif
-
        add_intrinsics (module->lmodule);
        add_types (module);
 
@@ -8549,7 +8648,7 @@ emit_aot_file_info (MonoLLVMModule *module)
        if (info->trampoline_size [0]) {
                fields [tindex ++] = AddJitGlobal (module, eltype, "specific_trampolines");
                fields [tindex ++] = AddJitGlobal (module, eltype, "static_rgctx_trampolines");
-               fields [tindex ++] = AddJitGlobal (module, eltype, "imt_thunks");
+               fields [tindex ++] = AddJitGlobal (module, eltype, "imt_trampolines");
                fields [tindex ++] = AddJitGlobal (module, eltype, "gsharedvt_arg_trampolines");
        } else {
                fields [tindex ++] = LLVMConstNull (eltype);
@@ -8879,7 +8978,7 @@ emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, co
        filename = g_path_get_basename (source_file);
 
 #if LLVM_API_VERSION > 100
-       return mono_llvm_di_create_function (module->di_builder, module->cu, cfg->method->name, name, dir, filename, n_seq_points ? sym_seq_points [0].line : 1);
+       return mono_llvm_di_create_function (module->di_builder, module->cu, method, cfg->method->name, name, dir, filename, n_seq_points ? sym_seq_points [0].line : 1);
 #endif
 
        ctx_args [0] = LLVMConstInt (LLVMInt32Type (), 0x29, FALSE);
@@ -8998,7 +9097,8 @@ default_mono_llvm_unhandled_exception (void)
        MonoObject *target = mono_gchandle_get_target (jit_tls->thrown_exc);
 
        mono_unhandled_exception (target);
-       exit (mono_environment_exitcode_get ());
+       mono_invoke_unhandled_exception_hook (target);
+       g_assert_not_reached ();
 }
 
 /*
@@ -9103,3 +9203,27 @@ default_mono_llvm_unhandled_exception (void)
  *   code.
  * - use pointer types to help optimizations.
  */
+
+#else /* DISABLE_JIT */
+
+void
+mono_llvm_cleanup (void)
+{
+}
+
+void
+mono_llvm_free_domain_info (MonoDomain *domain)
+{
+}
+
+void
+mono_llvm_init (void)
+{
+}
+
+void
+default_mono_llvm_unhandled_exception (void)
+{
+}
+
+#endif /* DISABLE_JIT */