Merge pull request #1659 from alexanderkyte/stringbuilder-referencesource
[mono.git] / mono / mini / mini-llvm.c
index 8f1f9a76238bba6f2710554fb1a96b7ee480dd39..2fa1da978d424eed7b04ba70685dd45e0a4da8e1 100644 (file)
 extern void *memset(void *, int, size_t);
 void bzero (void *to, size_t count) { memset (to, 0, count); }
 
+#endif
+
+#if LLVM_API_VERSION < 4
+#error "The version of the mono llvm repository is too old."
 #endif
 
  /*
@@ -372,10 +376,10 @@ create_llvm_type_for_type (MonoClass *klass)
 static LLVMTypeRef
 type_to_llvm_type (EmitContext *ctx, MonoType *t)
 {
-       t = mini_replace_type (t);
-
        if (t->byref)
                return LLVMPointerType (LLVMInt8Type (), 0);
+
+       t = mini_get_underlying_type (ctx->cfg, t);
        switch (t->type) {
        case MONO_TYPE_VOID:
                return LLVMVoidType ();
@@ -1152,26 +1156,36 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
        if (sinfo)
                memset (sinfo, 0, sizeof (LLVMSigInfo));
 
-       rtype = mini_replace_type (sig->ret);
+       rtype = mini_get_underlying_type (ctx->cfg, sig->ret);
        ret_type = type_to_llvm_type (ctx, rtype);
        CHECK_FAILURE (ctx);
 
-       if (cinfo && cinfo->ret.storage == LLVMArgVtypeInReg) {
-               /* LLVM models this by returning an aggregate value */
-               if (cinfo->ret.pair_storage [0] == LLVMArgInIReg && cinfo->ret.pair_storage [1] == LLVMArgNone) {
-                       LLVMTypeRef members [2];
+       if (cinfo) {
+               if (cinfo->ret.storage == LLVMArgVtypeInReg) {
+                       /* LLVM models this by returning an aggregate value */
+                       if (cinfo->ret.pair_storage [0] == LLVMArgInIReg && cinfo->ret.pair_storage [1] == LLVMArgNone) {
+                               LLVMTypeRef members [2];
 
-                       members [0] = IntPtrType ();
-                       ret_type = LLVMStructType (members, 1, FALSE);
-               } else {
-                       g_assert_not_reached ();
+                               members [0] = IntPtrType ();
+                               ret_type = LLVMStructType (members, 1, FALSE);
+                       } else {
+                               g_assert_not_reached ();
+                       }
+               } else if (cinfo->ret.storage == LLVMArgVtypeByVal) {
+                       /* Vtype returned normally by val */
+               } else if (cinfo->ret.storage == LLVMArgFpStruct) {
+                       /* Vtype returned as a fp struct */
+                       LLVMTypeRef members [16];
+
+                       /* Have to create our own structure since we don't map fp structures to LLVM fp structures yet */
+                       for (i = 0; i < cinfo->ret.nslots; ++i)
+                               members [i] = cinfo->ret.esize == 8 ? LLVMDoubleType () : LLVMFloatType ();
+                       ret_type = LLVMStructType (members, cinfo->ret.nslots, FALSE);
+               } else if (mini_type_is_vtype (ctx->cfg, rtype)) {
+                       g_assert (cinfo->ret.storage == LLVMArgVtypeRetAddr);
+                       vretaddr = TRUE;
+                       ret_type = LLVMVoidType ();
                }
-       } else if (cinfo && cinfo->ret.storage == LLVMArgVtypeByVal) {
-               /* Vtype returned normally by val */
-       } else if (cinfo && mini_type_is_vtype (ctx->cfg, rtype)) {
-               g_assert (cinfo->ret.storage == LLVMArgVtypeRetAddr);
-               vretaddr = TRUE;
-               ret_type = LLVMVoidType ();
        }
 
        pindexes = g_new0 (int, sig->param_count);
@@ -1226,7 +1240,14 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                if (vretaddr && vret_arg_pindex == pindex)
                        param_types [pindex ++] = IntPtrType ();
                pindexes [i] = pindex;
-               if (ainfo && ainfo->storage == LLVMArgVtypeInReg) {
+
+               if (!ainfo) {
+                       param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]);
+                       continue;
+               }
+
+               switch (ainfo->storage) {
+               case LLVMArgVtypeInReg:
                        for (j = 0; j < 2; ++j) {
                                switch (ainfo->pair_storage [j]) {
                                case LLVMArgInIReg:
@@ -1238,23 +1259,29 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                                        g_assert_not_reached ();
                                }
                        }
-               } else if (ainfo && ainfo->storage == LLVMArgVtypeByVal) {
+                       break;
+               case LLVMArgVtypeByVal:
                        param_types [pindex] = type_to_llvm_arg_type (ctx, sig->params [i]);
                        CHECK_FAILURE (ctx);
                        param_types [pindex] = LLVMPointerType (param_types [pindex], 0);
                        pindex ++;
-               } else if (ainfo && ainfo->storage == LLVMArgAsIArgs) {
+                       break;
+               case LLVMArgAsIArgs:
                        param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
                        pindex ++;
-               } else if (ainfo && ainfo->storage == LLVMArgAsFpArgs) {
+                       break;
+               case LLVMArgAsFpArgs: {
                        int j;
 
                        for (j = 0; j < ainfo->nslots; ++j)
                                param_types [pindex + j] = ainfo->esize == 8 ? LLVMDoubleType () : LLVMFloatType ();
                        pindex += ainfo->nslots;
-               } else {
+                       break;
+               }
+               default:
                        param_types [pindex ++] = type_to_llvm_arg_type (ctx, sig->params [i]);
-               }                       
+                       break;
+               }
        }
        if (vretaddr && vret_arg_pindex == pindex)
                param_types [pindex ++] = IntPtrType ();
@@ -1493,12 +1520,6 @@ emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LL
        return lcall;
 }
 
-#if LLVM_API_VERSION >= 4
-#define EXTRA_MONO_LOAD_STORE_ARGS 1
-#else
-#define EXTRA_MONO_LOAD_STORE_ARGS 0
-#endif
-
 static LLVMValueRef
 emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting, BarrierKind barrier)
 {
@@ -1507,7 +1528,6 @@ emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder
        LLVMTypeRef addr_type;
 
        if (is_faulting && bb->region != -1) {
-#if LLVM_API_VERSION >= 4
                LLVMAtomicOrdering ordering;
 
                switch (barrier) {
@@ -1524,7 +1544,6 @@ emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder
                        g_assert_not_reached ();
                        break;
                }
-#endif
 
                /*
                 * We handle loads which can fault by calling a mono specific intrinsic
@@ -1556,10 +1575,8 @@ emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder
                args [0] = addr;
                args [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
                args [2] = LLVMConstInt (LLVMInt1Type (), TRUE, FALSE);
-#if LLVM_API_VERSION >= 4
                args [3] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
-#endif
-               res = emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 3 + EXTRA_MONO_LOAD_STORE_ARGS);
+               res = emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 4);
 
                if (addr_type == LLVMPointerType (LLVMDoubleType (), 0))
                        res = LLVMBuildBitCast (*builder_ref, res, LLVMDoubleType (), "");
@@ -1600,7 +1617,6 @@ emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builde
        LLVMValueRef args [16];
 
        if (is_faulting && bb->region != -1) {
-#if LLVM_API_VERSION >= 4
                LLVMAtomicOrdering ordering;
 
                switch (barrier) {
@@ -1617,7 +1633,6 @@ emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builde
                        g_assert_not_reached ();
                        break;
                }
-#endif
 
                switch (size) {
                case 1:
@@ -1645,10 +1660,8 @@ emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builde
                args [1] = addr;
                args [2] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
                args [3] = LLVMConstInt (LLVMInt1Type (), TRUE, FALSE);
-#if LLVM_API_VERSION >= 4
                args [4] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
-#endif
-               emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 4 + EXTRA_MONO_LOAD_STORE_ARGS);
+               emit_call (ctx, bb, builder_ref, LLVMGetNamedFunction (ctx->module, intrins_name), args, 5);
        } else {
                mono_llvm_build_store (*builder_ref, value, addr, is_faulting, barrier);
        }
@@ -1969,7 +1982,9 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                LLVMArgInfo *ainfo = &linfo->args [i + sig->hasthis];
                int reg = cfg->args [i + sig->hasthis]->dreg;
 
-               if (ainfo->storage == LLVMArgVtypeInReg || ainfo->storage == LLVMArgAsFpArgs) {
+               switch (ainfo->storage) {
+               case LLVMArgVtypeInReg:
+               case LLVMArgAsFpArgs: {
                        LLVMValueRef args [8];
                        int j;
 
@@ -1993,22 +2008,29 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                                /* Treat these as normal values */
                                ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
                        }
-               } else if (ainfo->storage == LLVMArgVtypeByVal) {
+                       break;
+               }
+               case LLVMArgVtypeByVal: {
                        ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, ctx->pindexes [i]);
 
                        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 == LLVMArgAsIArgs) {
+                       break;
+               }
+               case LLVMArgAsIArgs: {
                        LLVMValueRef arg = LLVMGetParam (ctx->lmethod, ctx->pindexes [i]);
 
                        ctx->addresses [reg] = build_alloca (ctx, sig->params [i]);
 
                        /* The argument is received as an array of ints, store it into the real argument */
                        LLVMBuildStore (ctx->builder, arg, convert (ctx, ctx->addresses [reg], LLVMPointerType (LLVMTypeOf (arg), 0)));
-               } else {
+                       break;
+               }
+               default:
                        ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->params [i])), type_is_unsigned (ctx, sig->params [i]));
+                       break;
                }
        }
 
@@ -2125,7 +2147,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        CHECK_FAILURE (ctx);
 
        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 || ins->opcode == OP_RCALL_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 || ins->opcode == OP_RCALL_REG);
+       calli = !call->fptr_is_patch && (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 || ins->opcode == OP_RCALL_REG);
 
        /* FIXME: Avoid creating duplicate methods */
 
@@ -2229,7 +2251,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        /* 
         * Collect and convert arguments
         */
-       nargs = (sig->param_count * 2) + sig->hasthis + vretaddr + call->rgctx_reg + call->imt_arg_reg;
+       nargs = (sig->param_count * 16) + sig->hasthis + vretaddr + call->rgctx_reg + call->imt_arg_reg;
        len = sizeof (LLVMValueRef) * nargs;
        args = alloca (len);
        memset (args, 0, len);
@@ -2289,7 +2311,9 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                regpair = (guint32)(gssize)(l->data);
                reg = regpair & 0xffffff;
                args [pindex] = values [reg];
-               if (ainfo->storage == LLVMArgVtypeInReg || ainfo->storage == LLVMArgAsFpArgs) {
+               switch (ainfo->storage) {
+               case LLVMArgVtypeInReg:
+               case LLVMArgAsFpArgs: {
                        guint32 nargs;
 
                        g_assert (addresses [reg]);
@@ -2298,19 +2322,25 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
 
                        // FIXME: alignment
                        // FIXME: Get rid of the VMOVE
-               } else if (ainfo->storage == LLVMArgVtypeByVal) {
+                       break;
+               }
+               case LLVMArgVtypeByVal:
                        g_assert (addresses [reg]);
                        args [pindex] = addresses [reg];
-               } else if (ainfo->storage == LLVMArgAsIArgs) {
+                       break;
+               case LLVMArgAsIArgs:
                        g_assert (addresses [reg]);
                        args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
-               } else {
+                       break;
+               default:
                        g_assert (args [pindex]);
                        if (i == 0 && sig->hasthis)
                                args [pindex] = convert (ctx, args [pindex], ThisType ());
                        else
                                args [pindex] = convert (ctx, args [pindex], type_to_llvm_arg_type (ctx, sig->params [i - sig->hasthis]));
+                       break;
                }
+               g_assert (pindex <= nargs);
 
                l = l->next;
        }
@@ -2351,24 +2381,40 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        /*
         * Convert the result
         */
-       if (cinfo && cinfo->ret.storage == LLVMArgVtypeInReg) {
-               LLVMValueRef regs [2];
+       if (cinfo) {
+               switch (cinfo->ret.storage) {
+               case LLVMArgVtypeInReg: {
+                       LLVMValueRef regs [2];
 
-               if (!addresses [ins->dreg])
-                       addresses [ins->dreg] = build_alloca (ctx, sig->ret);
+                       if (!addresses [ins->dreg])
+                               addresses [ins->dreg] = build_alloca (ctx, sig->ret);
 
-               regs [0] = LLVMBuildExtractValue (builder, lcall, 0, "");
-               if (cinfo->ret.pair_storage [1] != LLVMArgNone)
-                       regs [1] = LLVMBuildExtractValue (builder, lcall, 1, "");
-                                       
-               emit_args_to_vtype (ctx, builder, sig->ret, addresses [ins->dreg], &cinfo->ret, regs);
-       } else if (cinfo && cinfo->ret.storage == LLVMArgVtypeByVal) {
-               if (!addresses [call->inst.dreg])
-                       addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
-               LLVMBuildStore (builder, lcall, addresses [call->inst.dreg]);
-       } else if (sig->ret->type != MONO_TYPE_VOID && !vretaddr) {
-               /* If the method returns an unsigned value, need to zext it */
-               values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->ret)), type_is_unsigned (ctx, sig->ret));
+                       regs [0] = LLVMBuildExtractValue (builder, lcall, 0, "");
+                       if (cinfo->ret.pair_storage [1] != LLVMArgNone)
+                               regs [1] = LLVMBuildExtractValue (builder, lcall, 1, "");
+                       emit_args_to_vtype (ctx, builder, sig->ret, addresses [ins->dreg], &cinfo->ret, regs);
+                       break;
+               }
+               case LLVMArgVtypeByVal:
+                       if (!addresses [call->inst.dreg])
+                               addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+                       LLVMBuildStore (builder, lcall, addresses [call->inst.dreg]);
+                       break;
+               case LLVMArgFpStruct:
+                       if (!addresses [call->inst.dreg])
+                               addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
+                       LLVMBuildStore (builder, lcall, convert_full (ctx, addresses [call->inst.dreg], LLVMPointerType (LLVMTypeOf (lcall), 0), FALSE));
+                       break;
+               default:
+                       if (sig->ret->type != MONO_TYPE_VOID && !vretaddr)
+                               /* If the method returns an unsigned value, need to zext it */
+                               values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->ret)), type_is_unsigned (ctx, sig->ret));
+                       break;
+               }
+       } else {
+               if (sig->ret->type != MONO_TYPE_VOID && !vretaddr)
+                       /* If the method returns an unsigned value, need to zext it */
+                       values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, sig->ret)), type_is_unsigned (ctx, sig->ret));
        }
 
        if (vretaddr) {
@@ -2685,6 +2731,16 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                break;
                        }
 
+                       if (linfo->ret.storage == LLVMArgFpStruct) {
+                               LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (method)));
+                               LLVMValueRef retval;
+
+                               g_assert (addresses [ins->sreg1]);
+                               retval = LLVMBuildLoad (builder, convert (ctx, addresses [ins->sreg1], LLVMPointerType (ret_type, 0)), "");
+                               LLVMBuildRet (builder, retval);
+                               break;
+                       }
+
                        if (!lhs || ctx->is_dead [ins->sreg1]) {
                                /* 
                                 * The method did not set its return value, probably because it
@@ -2956,6 +3012,29 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        lhs = convert (ctx, lhs, regtype_to_llvm_type (spec [MONO_INST_DEST]));
                        rhs = convert (ctx, rhs, regtype_to_llvm_type (spec [MONO_INST_DEST]));
 
+#ifdef MONO_ARCH_NEED_DIV_CHECK
+                       switch (ins->opcode) {
+                       case OP_IDIV:
+                       case OP_LDIV:
+                       case OP_IREM:
+                       case OP_LREM:
+                       case OP_IDIV_UN:
+                       case OP_LDIV_UN:
+                       case OP_IREM_UN:
+                       case OP_LREM_UN: {
+                               LLVMValueRef cmp;
+
+                               cmp = LLVMBuildICmp (builder, LLVMIntEQ, rhs, LLVMConstInt (LLVMTypeOf (rhs), 0, FALSE), "");
+                               emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp);
+                               CHECK_FAILURE (ctx);
+                               builder = ctx->builder;
+                               break;
+                       }
+                       default:
+                               break;
+                       }
+#endif
+
                        switch (ins->opcode) {
                        case OP_IADD:
                        case OP_LADD:
@@ -2978,31 +3057,13 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                values [ins->dreg] = LLVMBuildURem (builder, lhs, rhs, dname);
                                break;
                        case OP_IDIV:
-                       case OP_LDIV: {
-#ifdef MONO_ARCH_NEED_DIV_CHECK
-                               LLVMValueRef cmp;
-
-                               cmp = LLVMBuildICmp (builder, LLVMIntEQ, rhs, LLVMConstInt (LLVMTypeOf (rhs), 0, FALSE), "");
-                               emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp);
-                               CHECK_FAILURE (ctx);
-                               builder = ctx->builder;
-#endif
+                       case OP_LDIV:
                                values [ins->dreg] = LLVMBuildSDiv (builder, lhs, rhs, dname);
                                break;
-                       }
                        case OP_IDIV_UN:
-                       case OP_LDIV_UN: {
-#ifdef MONO_ARCH_NEED_DIV_CHECK
-                               LLVMValueRef cmp;
-
-                               cmp = LLVMBuildICmp (builder, LLVMIntEQ, rhs, LLVMConstInt (LLVMTypeOf (rhs), 0, FALSE), "");
-                               emit_cond_system_exception (ctx, bb, "DivideByZeroException", cmp);
-                               CHECK_FAILURE (ctx);
-                               builder = ctx->builder;
-#endif
+                       case OP_LDIV_UN:
                                values [ins->dreg] = LLVMBuildUDiv (builder, lhs, rhs, dname);
                                break;
-                       }
                        case OP_FDIV:
                        case OP_RDIV:
                                values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, dname);
@@ -3686,12 +3747,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        /* new value */
                        args [2] = convert (ctx, values [ins->sreg2], t);
                        val = mono_llvm_build_cmpxchg (builder, args [0], args [1], args [2]);
-#if LLVM_API_VERSION >= 1
                        /* cmpxchg returns a pair */
                        values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, "");
-#else
-                       values [ins->dreg] = val;
-#endif
                        break;
                }
                case OP_MEMORY_BARRIER: {
@@ -3709,7 +3766,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ATOMIC_LOAD_R4:
                case OP_ATOMIC_LOAD_R8: {
                        LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
-#if LLVM_API_VERSION >= 4
+
                        int size;
                        gboolean sext, zext;
                        LLVMTypeRef t;
@@ -3737,9 +3794,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
                        else if (zext)
                                values [ins->dreg] = LLVMBuildZExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
-#else
-                       LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
-#endif
                        break;
                }
                case OP_ATOMIC_STORE_I1:
@@ -3753,7 +3807,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ATOMIC_STORE_R4:
                case OP_ATOMIC_STORE_R8: {
                        LLVM_FAILURE (ctx, "atomic mono.load intrinsic");
-#if LLVM_API_VERSION >= 4
+
                        int size;
                        gboolean sext, zext;
                        LLVMTypeRef t;
@@ -3772,10 +3826,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        emit_store_general (ctx, bb, &builder, size, value, addr, is_volatile, barrier);
                        break;
-#else
-                       LLVM_FAILURE (ctx, "atomic mono.store intrinsic");
-#endif
-                       break;
                }
                case OP_RELAXED_NOP: {
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
@@ -4809,10 +4859,6 @@ mono_llvm_emit_method (MonoCompile *cfg)
 
        if (cfg->compile_aot) {
                LLVMSetLinkage (method, LLVMInternalLinkage);
-#if LLVM_API_VERSION == 0
-               /* This causes an assertion in later LLVM versions */
-               LLVMSetVisibility (method, LLVMHiddenVisibility);
-#endif
                if (ctx->lmodule->external_symbols) {
                        LLVMSetLinkage (method, LLVMExternalLinkage);
                        LLVMSetVisibility (method, LLVMHiddenVisibility);
@@ -4833,6 +4879,9 @@ mono_llvm_emit_method (MonoCompile *cfg)
                if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
                        LLVM_FAILURE (ctx, "non-finally/catch clause.");
        }
+       if (header->num_clauses || (cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING))
+               /* We can't handle inlined methods with clauses */
+               LLVMAddFunctionAttr (method, LLVMNoInlineAttribute);
 
        if (linfo->rgctx_arg) {
                ctx->rgctx_arg = LLVMGetParam (method, sinfo.rgctx_arg_pindex);
@@ -5597,21 +5646,17 @@ add_intrinsics (LLVMModuleRef module)
                        arg_types [0] = LLVMPointerType (LLVMIntType (i * 8), 0);
                        arg_types [1] = LLVMInt32Type ();
                        arg_types [2] = LLVMInt1Type ();
-#if LLVM_API_VERSION >= 4
                        arg_types [3] = LLVMInt32Type ();
-#endif
                        sprintf (name, "llvm.mono.load.i%d.p0i%d", i * 8, i * 8);
-                       LLVMAddFunction (module, name, LLVMFunctionType (LLVMIntType (i * 8), arg_types, 3 + EXTRA_MONO_LOAD_STORE_ARGS, FALSE));
+                       LLVMAddFunction (module, name, LLVMFunctionType (LLVMIntType (i * 8), arg_types, 4, FALSE));
 
                        arg_types [0] = LLVMIntType (i * 8);
                        arg_types [1] = LLVMPointerType (LLVMIntType (i * 8), 0);
                        arg_types [2] = LLVMInt32Type ();
                        arg_types [3] = LLVMInt1Type ();
-#if LLVM_API_VERSION >= 4
                        arg_types [4] = LLVMInt32Type ();
-#endif
                        sprintf (name, "llvm.mono.store.i%d.p0i%d", i * 8, i * 8);
-                       LLVMAddFunction (module, name, LLVMFunctionType (LLVMVoidType (), arg_types, 4 + EXTRA_MONO_LOAD_STORE_ARGS, FALSE));
+                       LLVMAddFunction (module, name, LLVMFunctionType (LLVMVoidType (), arg_types, 5, FALSE));
                }
        }
 }
@@ -5753,6 +5798,7 @@ mono_llvm_create_aot_module (const char *got_symbol, gboolean external_symbols,
                lbuilder = LLVMCreateBuilder ();
                LLVMPositionBuilderAtEnd (lbuilder, lbb);
                LLVMBuildRetVoid (lbuilder);
+               mark_as_used (&aot_module, personality);
        }
 
        aot_module.llvm_types = g_hash_table_new (NULL, NULL);
@@ -6135,9 +6181,9 @@ emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsigned char *cil
 
 /*
   AOT SUPPORT:
-  Emit LLVM bytecode into a .bc file, compile it using llc into a .s file, then 
-  append the AOT data structures to that file. For methods which cannot be
-  handled by LLVM, the normal JIT compiled versions are used.
+  Emit LLVM bytecode into a .bc file, compile it using llc into a .s file, then link
+  it with the file containing the methods emitted by the JIT and the AOT data
+  structures.
 */
 
 /* FIXME: Normalize some aspects of the mono IR to allow easier translation, like: