Merge pull request #1603 from iainx/coverage-null-protect
[mono.git] / mono / mini / mini-llvm.c
index ee39c96a8d445dd69b5f5130c9f7e5a172ae7e60..36be92bfe6867a2ec4b2fbcc227d65d650f1b5f8 100644 (file)
@@ -327,6 +327,43 @@ type_to_simd_type (int type)
        }
 }
 
+static LLVMTypeRef
+create_llvm_type_for_type (MonoClass *klass)
+{
+       int i, size, nfields, esize;
+       LLVMTypeRef *eltypes;
+       char *name;
+       MonoType *t;
+       LLVMTypeRef ltype;
+
+       t = &klass->byval_arg;
+
+       if (mini_type_is_hfa (t, &nfields, &esize)) {
+               /*
+                * This is needed on arm64 where HFAs are returned in
+                * registers.
+                */
+               size = nfields;
+               eltypes = g_new (LLVMTypeRef, size);
+               for (i = 0; i < size; ++i)
+                       eltypes [i] = esize == 4 ? LLVMFloatType () : LLVMDoubleType ();
+       } else {
+               size = get_vtype_size (t);
+
+               eltypes = g_new (LLVMTypeRef, size);
+               for (i = 0; i < size; ++i)
+                       eltypes [i] = LLVMInt8Type ();
+       }
+
+       name = mono_type_full_name (&klass->byval_arg);
+       ltype = LLVMStructCreateNamed (LLVMGetGlobalContext (), name);
+       LLVMStructSetBody (ltype, eltypes, size, FALSE);
+       g_free (eltypes);
+       g_free (name);
+
+       return ltype;
+}
+
 /*
  * type_to_llvm_type:
  *
@@ -398,22 +435,8 @@ type_to_llvm_type (EmitContext *ctx, MonoType *t)
 
                ltype = g_hash_table_lookup (ctx->lmodule->llvm_types, klass);
                if (!ltype) {
-                       int i, size;
-                       LLVMTypeRef *eltypes;
-                       char *name;
-
-                       size = get_vtype_size (t);
-
-                       eltypes = g_new (LLVMTypeRef, size);
-                       for (i = 0; i < size; ++i)
-                               eltypes [i] = LLVMInt8Type ();
-
-                       name = mono_type_full_name (&klass->byval_arg);
-                       ltype = LLVMStructCreateNamed (LLVMGetGlobalContext (), name);
-                       LLVMStructSetBody (ltype, eltypes, size, FALSE);
+                       ltype = create_llvm_type_for_type (klass);
                        g_hash_table_insert (ctx->lmodule->llvm_types, klass, ltype);
-                       g_free (eltypes);
-                       g_free (name);
                }
                return ltype;
        }
@@ -482,7 +505,7 @@ type_to_llvm_arg_type (EmitContext *ctx, MonoType *t)
  * on the IL stack.
  */
 static G_GNUC_UNUSED LLVMTypeRef
-llvm_type_to_stack_type (LLVMTypeRef type)
+llvm_type_to_stack_type (MonoCompile *cfg, LLVMTypeRef type)
 {
        if (type == NULL)
                return NULL;
@@ -490,7 +513,7 @@ llvm_type_to_stack_type (LLVMTypeRef type)
                return LLVMInt32Type ();
        else if (type == LLVMInt16Type ())
                return LLVMInt32Type ();
-       else if (type == LLVMFloatType ())
+       else if (!cfg->r4fp && type == LLVMFloatType ())
                return LLVMDoubleType ();
        else
                return type;
@@ -558,9 +581,13 @@ op_to_llvm_type (int opcode)
                return LLVMInt64Type ();
        case OP_FCONV_TO_I1:
        case OP_FCONV_TO_U1:
+       case OP_RCONV_TO_I1:
+       case OP_RCONV_TO_U1:
                return LLVMInt8Type ();
        case OP_FCONV_TO_I2:
        case OP_FCONV_TO_U2:
+       case OP_RCONV_TO_I2:
+       case OP_RCONV_TO_U2:
                return LLVMInt16Type ();
        case OP_FCONV_TO_I:
        case OP_FCONV_TO_U:
@@ -1129,22 +1156,32 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
        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);
@@ -1199,7 +1236,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:
@@ -1211,23 +1255,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 ();
@@ -1734,7 +1784,7 @@ emit_args_to_vtype (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMV
                nslots = 2;
 
        for (j = 0; j < nslots; ++j) {
-               LLVMValueRef index [2], addr;
+               LLVMValueRef index [2], addr, daddr;
                int part_size = size > sizeof (gpointer) ? sizeof (gpointer) : size;
                LLVMTypeRef part_type;
 
@@ -1748,15 +1798,14 @@ emit_args_to_vtype (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMV
                                index [0] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
                                addr = LLVMBuildGEP (builder, address, index, 1, "");
                        } else {
-                               index [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
-                               index [1] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
-                               addr = LLVMBuildGEP (builder, address, index, 2, "");
+                               daddr = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (IntPtrType (), 0), "");
+                               index [0] = LLVMConstInt (LLVMInt32Type (), j, FALSE);
+                               addr = LLVMBuildGEP (builder, daddr, index, 1, "");
                        }
                        LLVMBuildStore (builder, convert (ctx, args [j], part_type), LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (part_type, 0), ""));
                        break;
                }
                case LLVMArgInFPReg: {
-                       LLVMValueRef daddr;
                        LLVMTypeRef arg_type;
 
                        if (ainfo->esize == 8)
@@ -1815,9 +1864,9 @@ emit_vtype_to_args (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMV
                                index [0] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
                                addr = LLVMBuildGEP (builder, address, index, 1, "");
                        } else {
-                               index [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
-                               index [1] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);
-                               addr = LLVMBuildGEP (builder, address, index, 2, "");
+                               daddr = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (IntPtrType (), 0), "");
+                               index [0] = LLVMConstInt (LLVMInt32Type (), j, FALSE);
+                               addr = LLVMBuildGEP (builder, daddr, index, 1, "");
                        }
                        args [pindex ++] = convert (ctx, LLVMBuildLoad (builder, LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (LLVMIntType (partsize * 8), 0), ""), ""), IntPtrType ());
                        break;
@@ -1943,7 +1992,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;
 
@@ -1967,22 +2018,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 {
-                       ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i])), type_is_unsigned (ctx, sig->params [i]));
+                       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;
                }
        }
 
@@ -2056,9 +2114,6 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
 }
 
 /* Have to export this for AOT */
-void
-mono_personality (void);
-       
 void
 mono_personality (void)
 {
@@ -2101,8 +2156,8 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
        llvm_sig = sig_to_llvm_sig_full (ctx, sig, cinfo, &sinfo);
        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);
-       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);
+       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 = !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 */
 
@@ -2266,7 +2321,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]);
@@ -2275,18 +2332,23 @@ 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;
                }
 
                l = l->next;
@@ -2328,25 +2390,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);
-
-               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 */
+                       if (!addresses [ins->dreg])
+                               addresses [ins->dreg] = build_alloca (ctx, sig->ret);
 
-               values [ins->dreg] = convert_full (ctx, lcall, llvm_type_to_stack_type (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) {
@@ -2578,7 +2655,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMConstReal (LLVMDoubleType (), *(double*)ins->inst_p0);
                        break;
                case OP_R4CONST:
-                       values [ins->dreg] = LLVMConstFPExt (LLVMConstReal (LLVMFloatType (), *(float*)ins->inst_p0), LLVMDoubleType ());
+                       if (cfg->r4fp)
+                               values [ins->dreg] = LLVMConstReal (LLVMFloatType (), *(float*)ins->inst_p0);
+                       else
+                               values [ins->dreg] = LLVMConstFPExt (LLVMConstReal (LLVMFloatType (), *(float*)ins->inst_p0), LLVMDoubleType ());
                        break;
                case OP_DUMMY_ICONST:
                        values [ins->dreg] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
@@ -2660,6 +2740,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
@@ -2676,6 +2766,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        break;
                case OP_ICOMPARE:
                case OP_FCOMPARE:
+               case OP_RCOMPARE:
                case OP_LCOMPARE:
                case OP_COMPARE:
                case OP_ICOMPARE_IMM:
@@ -2718,9 +2809,11 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        }
 
                        /* We use COMPARE+SETcc/Bcc, llvm uses SETcc+br cond */
-                       if (ins->opcode == OP_FCOMPARE)
+                       if (ins->opcode == OP_FCOMPARE) {
                                cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMDoubleType ()), convert (ctx, rhs, LLVMDoubleType ()), "");
-                       else if (ins->opcode == OP_COMPARE_IMM) {
+                       } else if (ins->opcode == OP_RCOMPARE) {
+                               cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMFloatType ()), convert (ctx, rhs, LLVMFloatType ()), "");
+                       } else if (ins->opcode == OP_COMPARE_IMM) {
                                if (LLVMGetTypeKind (LLVMTypeOf (lhs)) == LLVMPointerTypeKind && ins->inst_imm == 0)
                                        cmp = LLVMBuildICmp (builder, cond_to_llvm_cond [rel], lhs, LLVMConstNull (LLVMTypeOf (lhs)), "");
                                else
@@ -2786,6 +2879,20 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildZExt (builder, cmp, LLVMInt32Type (), dname);
                        break;
                }
+               case OP_RCEQ:
+               case OP_RCLT:
+               case OP_RCLT_UN:
+               case OP_RCGT:
+               case OP_RCGT_UN: {
+                       CompRelation rel;
+                       LLVMValueRef cmp;
+
+                       rel = mono_opcode_to_cond (ins->opcode);
+
+                       cmp = LLVMBuildFCmp (builder, fpcond_to_llvm_cond [rel], convert (ctx, lhs, LLVMFloatType ()), convert (ctx, rhs, LLVMFloatType ()), "");
+                       values [ins->dreg] = LLVMBuildZExt (builder, cmp, LLVMInt32Type (), dname);
+                       break;
+               }
                case OP_PHI:
                case OP_FPHI:
                case OP_VPHI:
@@ -2849,7 +2956,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        g_assert (lhs);
                        values [ins->dreg] = lhs;
                        break;
-               case OP_FMOVE: {
+               case OP_FMOVE:
+               case OP_RMOVE: {
                        MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
                                
                        g_assert (lhs);
@@ -2913,6 +3021,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:
@@ -2943,6 +3074,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                values [ins->dreg] = LLVMBuildUDiv (builder, lhs, rhs, dname);
                                break;
                        case OP_FDIV:
+                       case OP_RDIV:
                                values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, dname);
                                break;
                        case OP_IAND:
@@ -2984,6 +3116,31 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                g_assert_not_reached ();
                        }
                        break;
+               case OP_RADD:
+               case OP_RSUB:
+               case OP_RMUL:
+               case OP_RDIV: {
+                       lhs = convert (ctx, lhs, LLVMFloatType ());
+                       rhs = convert (ctx, rhs, LLVMFloatType ());
+                       switch (ins->opcode) {
+                       case OP_RADD:
+                               values [ins->dreg] = LLVMBuildFAdd (builder, lhs, rhs, dname);
+                               break;
+                       case OP_RSUB:
+                               values [ins->dreg] = LLVMBuildFSub (builder, lhs, rhs, dname);
+                               break;
+                       case OP_RMUL:
+                               values [ins->dreg] = LLVMBuildFMul (builder, lhs, rhs, dname);
+                               break;
+                       case OP_RDIV:
+                               values [ins->dreg] = LLVMBuildFDiv (builder, lhs, rhs, dname);
+                               break;
+                       default:
+                               g_assert_not_reached ();
+                               break;
+                       }
+                       break;
+               }
                case OP_IADD_IMM:
                case OP_ISUB_IMM:
                case OP_IMUL_IMM:
@@ -3105,6 +3262,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        lhs = convert (ctx, lhs, LLVMDoubleType ());
                        values [ins->dreg] = LLVMBuildFSub (builder, LLVMConstReal (LLVMDoubleType (), 0.0), lhs, dname);
                        break;
+               case OP_RNEG:
+                       lhs = convert (ctx, lhs, LLVMFloatType ());
+                       values [ins->dreg] = LLVMBuildFSub (builder, LLVMConstReal (LLVMFloatType (), 0.0), lhs, dname);
+                       break;
                case OP_INOT: {
                        guint32 v = 0xffffffff;
                        values [ins->dreg] = LLVMBuildXor (builder, LLVMConstInt (LLVMInt32Type (), v, FALSE), convert (ctx, lhs, LLVMInt32Type ()), dname);
@@ -3156,21 +3317,27 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildZExt (builder, lhs, LLVMInt64Type (), dname);
                        break;
                case OP_FCONV_TO_I4:
+               case OP_RCONV_TO_I4:
                        values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMInt32Type (), dname);
                        break;
                case OP_FCONV_TO_I1:
+               case OP_RCONV_TO_I1:
                        values [ins->dreg] = LLVMBuildSExt (builder, LLVMBuildFPToSI (builder, lhs, LLVMInt8Type (), dname), LLVMInt32Type (), "");
                        break;
                case OP_FCONV_TO_U1:
+               case OP_RCONV_TO_U1:
                        values [ins->dreg] = LLVMBuildZExt (builder, LLVMBuildFPToUI (builder, lhs, LLVMInt8Type (), dname), LLVMInt32Type (), "");
                        break;
                case OP_FCONV_TO_I2:
+               case OP_RCONV_TO_I2:
                        values [ins->dreg] = LLVMBuildSExt (builder, LLVMBuildFPToSI (builder, lhs, LLVMInt16Type (), dname), LLVMInt32Type (), "");
                        break;
                case OP_FCONV_TO_U2:
+               case OP_RCONV_TO_U2:
                        values [ins->dreg] = LLVMBuildZExt (builder, LLVMBuildFPToUI (builder, lhs, LLVMInt16Type (), dname), LLVMInt32Type (), "");
                        break;
                case OP_FCONV_TO_I8:
+               case OP_RCONV_TO_I8:
                        values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMInt64Type (), dname);
                        break;
                case OP_FCONV_TO_I:
@@ -3192,11 +3359,23 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ICONV_TO_R4:
                case OP_LCONV_TO_R4:
                        v = LLVMBuildSIToFP (builder, lhs, LLVMFloatType (), "");
-                       values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
+                       if (cfg->r4fp)
+                               values [ins->dreg] = v;
+                       else
+                               values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
                        break;
                case OP_FCONV_TO_R4:
                        v = LLVMBuildFPTrunc (builder, lhs, LLVMFloatType (), "");
-                       values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
+                       if (cfg->r4fp)
+                               values [ins->dreg] = v;
+                       else
+                               values [ins->dreg] = LLVMBuildFPExt (builder, v, LLVMDoubleType (), dname);
+                       break;
+               case OP_RCONV_TO_R8:
+                       values [ins->dreg] = LLVMBuildFPExt (builder, lhs, LLVMDoubleType (), dname);
+                       break;
+               case OP_RCONV_TO_R4:
+                       values [ins->dreg] = lhs;
                        break;
                case OP_SEXT_I4:
                        values [ins->dreg] = LLVMBuildSExt (builder, convert (ctx, lhs, LLVMInt32Type ()), LLVMInt64Type (), dname);
@@ -3312,7 +3491,7 @@ 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 if (ins->opcode == OP_LOADR4_MEMBASE)
+                       else if (!cfg->r4fp && ins->opcode == OP_LOADR4_MEMBASE)
                                values [ins->dreg] = LLVMBuildFPExt (builder, values [ins->dreg], LLVMDoubleType (), dname);
                        break;
                }
@@ -3381,16 +3560,19 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_CALL:
                case OP_LCALL:
                case OP_FCALL:
+               case OP_RCALL:
                case OP_VCALL:
                case OP_VOIDCALL_MEMBASE:
                case OP_CALL_MEMBASE:
                case OP_LCALL_MEMBASE:
                case OP_FCALL_MEMBASE:
+               case OP_RCALL_MEMBASE:
                case OP_VCALL_MEMBASE:
                case OP_VOIDCALL_REG:
                case OP_CALL_REG:
                case OP_LCALL_REG:
                case OP_FCALL_REG:
+               case OP_RCALL_REG:
                case OP_VCALL_REG: {
                        process_call (ctx, bb, &builder, ins);
                        CHECK_FAILURE (ctx);
@@ -3596,6 +3778,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ATOMIC_LOAD_U8:
                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;
@@ -3639,6 +3822,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ATOMIC_STORE_U8:
                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;
@@ -4119,11 +4303,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        break;
                }
 
-               case OP_ICONV_TO_R8_RAW:
-                       /* Same as OP_ICONV_TO_R8 */
-                       values [ins->dreg] = convert (ctx, LLVMBuildBitCast (builder, lhs, LLVMFloatType (), ""), LLVMDoubleType ());
-                       break;
-
                case OP_COMPPS:
                case OP_COMPPD: {
                        LLVMValueRef args [3];
@@ -4724,6 +4903,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);
@@ -4814,7 +4996,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_FPHI:
                        case OP_VPHI:
                        case OP_XPHI: {
-                               LLVMTypeRef phi_type = llvm_type_to_stack_type (type_to_llvm_type (ctx, &ins->klass->byval_arg));
+                               LLVMTypeRef phi_type = llvm_type_to_stack_type (cfg, type_to_llvm_type (ctx, &ins->klass->byval_arg));
 
                                CHECK_FAILURE (ctx);
 
@@ -5644,6 +5826,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);